A new version of Morphic was added to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.1771.mcz
==================== Summary ====================
Name: Morphic-ct.1771 Author: ct Time: 25 May 2021, 7:38:48.072683 pm UUID: 5a9ddaf0-a062-7047-b5b2-d2ae2da3fe15 Ancestors: Morphic-mt.1769
Fixes a bottleneck when opening a yellow button menu on a morph that contains a very large number of subsub*morphs. On not-so-fast systems, this can be reproduced using:
self systemNavigation browseAllSelect: #notNil
On faster systems, you might need to write a small toolbuilder application to reproduce the bottleneck. I have an app with >10k list items in my image which actually blocked the image for several seconds when I yellow-clicked the window.
Fixed the problem without duplicating the logic of #allStringsAfter: by using a generator.
=============== Diff against Morphic-mt.1769 ===============
Item was changed: ----- Method: Morph>>addYellowButtonMenuItemsTo:event: (in category 'menu') ----- addYellowButtonMenuItemsTo: aMenu event: evt "Populate aMenu with appropriate menu items for a yellow-button (context menu) click." aMenu defaultTarget: self. "" Preferences noviceMode ifFalse: [aMenu addStayUpItem]. "" self addModelYellowButtonItemsTo: aMenu event: evt. "" Preferences generalizedYellowButtonMenu ifFalse: [^ self]. "" aMenu addLine. aMenu add: 'inspect' translated action: #inspect. "" aMenu addLine. self world selectedObject == self ifTrue: [aMenu add: 'deselect' translated action: #removeHalo] ifFalse: [aMenu add: 'select' translated action: #addHalo]. "" (self isWorldMorph or: [self mustBeBackmost or: [self wantsToBeTopmost]]) ifFalse: ["" aMenu addLine. aMenu add: 'send to back' translated action: #goBehind. aMenu add: 'bring to front' translated action: #comeToFront. self addEmbeddingMenuItemsTo: aMenu hand: evt hand]. "" self isWorldMorph ifFalse: ["" Smalltalk at: #NCAAConnectorMorph ifPresent: [:connectorClass | aMenu addLine. aMenu add: 'connect to' translated action: #startWiring. aMenu addLine]. ""
self isFullOnScreen ifFalse: [aMenu add: 'move onscreen' translated action: #goHome]]. "" Preferences noviceMode ifFalse: ["" self addLayoutMenuItems: aMenu hand: evt hand. (owner notNil and: [owner isTextMorph]) ifTrue: [self addTextAnchorMenuItems: aMenu hand: evt hand]]. "" self isWorldMorph ifFalse: ["" aMenu addLine. self addToggleItemsToHaloMenu: aMenu]. "" aMenu addLine. self isWorldMorph ifFalse: [aMenu add: 'copy to paste buffer' translated action: #copyToPasteBuffer:]. + (Generator on: [:gen | self streamAllStringsAfter: nil on: gen]) in: [:gen | + "optimized!! #allStringsAfter: can be slow for large subtrees." + gen atEnd ifFalse: [ + aMenu add: 'copy text' translated action: #clipText]]. - (self allStringsAfter: nil) isEmpty - ifFalse: [aMenu add: 'copy text' translated action: #clipText]. "" self addExportMenuItems: aMenu hand: evt hand. "" (Preferences noviceMode not and: [self isWorldMorph not]) ifTrue: ["" aMenu addLine. aMenu add: 'adhere to edge...' translated action: #adhereToEdge]. "" self addCustomMenuItems: aMenu hand: evt hand!
Item was changed: ----- Method: Morph>>allStringsAfter: (in category 'debug and other') ----- + allStringsAfter: aSubmorph - allStringsAfter: aSubmorph - "return an OrderedCollection of strings of text in my submorphs. If aSubmorph is non-nil, begin with that container."
+ ^ OrderedCollection streamContents: [:stream | + self streamAllStringsAfter: aSubmorph on: stream]! - | list ok | - list := OrderedCollection new. - ok := aSubmorph isNil. - self allMorphsDo: - [:sub | | string | - ok ifFalse: [ok := sub == aSubmorph]. "and do this one too" - ok - ifTrue: - [(string := sub userString) ifNotNil: - [string isString ifTrue: [list add: string] ifFalse: [list addAll: string]]]]. - ^list!
Item was added: + ----- Method: Morph>>streamAllStringsAfter:on: (in category 'debug and other') ----- + streamAllStringsAfter: aSubmorph on: aStream + "Stream all strings of text in my submorphs on aStream. If aSubmorph is non-nil, begin with that container." + + | ok | + ok := aSubmorph isNil. + self allMorphsDo: [:sub | | string | + ok ifFalse: [ok := sub == aSubmorph]. + "and do this one too" + ok ifTrue: [ + (string := sub userString) + ifNotNil: [string isString + ifTrue: [aStream nextPut: string] + ifFalse: [aStream nextPutAll: string]]]].!
Hi Christoph.
Thanks. I think that the expected pattern is a little bit different, though. The explicit use of Generator is unfortunate but can be easily avoided. :-)
allStringsAfter: morph do: block "..."
allStringsAfter: morph ^ Array streamContents: [:stream | self allStringsAfter: morph do: [:string | stream nextPut: string]]
hasStringsAfter: morph self allStringsAfter: morph do: [:string | ^ true]. ^ false
Best, Marcel Am 25.05.2021 19:39:07 schrieb commits@source.squeak.org commits@source.squeak.org: A new version of Morphic was added to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.1771.mcz
==================== Summary ====================
Name: Morphic-ct.1771 Author: ct Time: 25 May 2021, 7:38:48.072683 pm UUID: 5a9ddaf0-a062-7047-b5b2-d2ae2da3fe15 Ancestors: Morphic-mt.1769
Fixes a bottleneck when opening a yellow button menu on a morph that contains a very large number of subsub*morphs. On not-so-fast systems, this can be reproduced using:
self systemNavigation browseAllSelect: #notNil
On faster systems, you might need to write a small toolbuilder application to reproduce the bottleneck. I have an app with >10k list items in my image which actually blocked the image for several seconds when I yellow-clicked the window.
Fixed the problem without duplicating the logic of #allStringsAfter: by using a generator.
=============== Diff against Morphic-mt.1769 ===============
Item was changed: ----- Method: Morph>>addYellowButtonMenuItemsTo:event: (in category 'menu') ----- addYellowButtonMenuItemsTo: aMenu event: evt "Populate aMenu with appropriate menu items for a yellow-button (context menu) click." aMenu defaultTarget: self. "" Preferences noviceMode ifFalse: [aMenu addStayUpItem]. "" self addModelYellowButtonItemsTo: aMenu event: evt. "" Preferences generalizedYellowButtonMenu ifFalse: [^ self]. "" aMenu addLine. aMenu add: 'inspect' translated action: #inspect. "" aMenu addLine. self world selectedObject == self ifTrue: [aMenu add: 'deselect' translated action: #removeHalo] ifFalse: [aMenu add: 'select' translated action: #addHalo]. "" (self isWorldMorph or: [self mustBeBackmost or: [self wantsToBeTopmost]]) ifFalse: ["" aMenu addLine. aMenu add: 'send to back' translated action: #goBehind. aMenu add: 'bring to front' translated action: #comeToFront. self addEmbeddingMenuItemsTo: aMenu hand: evt hand]. "" self isWorldMorph ifFalse: ["" Smalltalk at: #NCAAConnectorMorph ifPresent: [:connectorClass | aMenu addLine. aMenu add: 'connect to' translated action: #startWiring. aMenu addLine]. ""
self isFullOnScreen ifFalse: [aMenu add: 'move onscreen' translated action: #goHome]]. "" Preferences noviceMode ifFalse: ["" self addLayoutMenuItems: aMenu hand: evt hand. (owner notNil and: [owner isTextMorph]) ifTrue: [self addTextAnchorMenuItems: aMenu hand: evt hand]]. "" self isWorldMorph ifFalse: ["" aMenu addLine. self addToggleItemsToHaloMenu: aMenu]. "" aMenu addLine. self isWorldMorph ifFalse: [aMenu add: 'copy to paste buffer' translated action: #copyToPasteBuffer:]. + (Generator on: [:gen | self streamAllStringsAfter: nil on: gen]) in: [:gen | + "optimized!! #allStringsAfter: can be slow for large subtrees." + gen atEnd ifFalse: [ + aMenu add: 'copy text' translated action: #clipText]]. - (self allStringsAfter: nil) isEmpty - ifFalse: [aMenu add: 'copy text' translated action: #clipText]. "" self addExportMenuItems: aMenu hand: evt hand. "" (Preferences noviceMode not and: [self isWorldMorph not]) ifTrue: ["" aMenu addLine. aMenu add: 'adhere to edge...' translated action: #adhereToEdge]. "" self addCustomMenuItems: aMenu hand: evt hand!
Item was changed: ----- Method: Morph>>allStringsAfter: (in category 'debug and other') ----- + allStringsAfter: aSubmorph - allStringsAfter: aSubmorph - "return an OrderedCollection of strings of text in my submorphs. If aSubmorph is non-nil, begin with that container."
+ ^ OrderedCollection streamContents: [:stream | + self streamAllStringsAfter: aSubmorph on: stream]! - | list ok | - list := OrderedCollection new. - ok := aSubmorph isNil. - self allMorphsDo: - [:sub | | string | - ok ifFalse: [ok := sub == aSubmorph]. "and do this one too" - ok - ifTrue: - [(string := sub userString) ifNotNil: - [string isString ifTrue: [list add: string] ifFalse: [list addAll: string]]]]. - ^list!
Item was added: + ----- Method: Morph>>streamAllStringsAfter:on: (in category 'debug and other') ----- + streamAllStringsAfter: aSubmorph on: aStream + "Stream all strings of text in my submorphs on aStream. If aSubmorph is non-nil, begin with that container." + + | ok | + ok := aSubmorph isNil. + self allMorphsDo: [:sub | | string | + ok ifFalse: [ok := sub == aSubmorph]. + "and do this one too" + ok ifTrue: [ + (string := sub userString) + ifNotNil: [string isString + ifTrue: [aStream nextPut: string] + ifFalse: [aStream nextPutAll: string]]]].!
Hi Marcel,
yes, I also have thought about this pattern, but I actually don't see why it would be better or why Generator would be an anti-pattern. :-) Your approach requires one more selector than my approach. In general, I think that Generators are a promising way to objectify a lazily/partially evaluatable collection.
Best, Christoph
Hi Christoph.
Thanks. I think that the expected pattern is a little bit different, though. The explicit use of Generator is unfortunate but can be easily avoided. :-)
allStringsAfter: morph do: block   "..."
allStringsAfter: morph   ^ Array streamContents: [:stream |    self allStringsAfter: morph do: [:string |      stream nextPut: string]]
hasStringsAfter: morph   self allStringsAfter: morph do: [:string | ^ true].   ^ false
Best, Marcel Am 25.05.2021 19:39:07 schrieb commits at source.squeak.org <commits at source.squeak.org>: A new version of Morphic was added to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.1771.mcz
==================== Summary ====================
Name: Morphic-ct.1771 Author: ct Time: 25 May 2021, 7:38:48.072683 pm UUID: 5a9ddaf0-a062-7047-b5b2-d2ae2da3fe15 Ancestors: Morphic-mt.1769
Fixes a bottleneck when opening a yellow button menu on a morph that contains a very large number of subsub*morphs. On not-so-fast systems, this can be reproduced using:
self systemNavigation browseAllSelect: #notNil
On faster systems, you might need to write a small toolbuilder application to reproduce the bottleneck. I have an app with >10k list items in my image which actually blocked the image for several seconds when I yellow-clicked the window.
Fixed the problem without duplicating the logic of #allStringsAfter: by using a generator.
=============== Diff against Morphic-mt.1769 ===============
Item was changed: ----- Method: Morph>>addYellowButtonMenuItemsTo:event: (in category 'menu') ----- addYellowButtonMenuItemsTo: aMenu event: evt "Populate aMenu with appropriate menu items for a yellow-button (context menu) click." aMenu defaultTarget: self. "" Preferences noviceMode ifFalse: [aMenu addStayUpItem]. "" self addModelYellowButtonItemsTo: aMenu event: evt. "" Preferences generalizedYellowButtonMenu ifFalse: [^ self]. "" aMenu addLine. aMenu add: 'inspect' translated action: #inspect. "" aMenu addLine. self world selectedObject == self ifTrue: [aMenu add: 'deselect' translated action: #removeHalo] ifFalse: [aMenu add: 'select' translated action: #addHalo]. "" (self isWorldMorph or: [self mustBeBackmost or: [self wantsToBeTopmost]]) ifFalse: ["" aMenu addLine. aMenu add: 'send to back' translated action: #goBehind. aMenu add: 'bring to front' translated action: #comeToFront. self addEmbeddingMenuItemsTo: aMenu hand: evt hand]. "" self isWorldMorph ifFalse: ["" Smalltalk at: #NCAAConnectorMorph ifPresent: [:connectorClass | aMenu addLine. aMenu add: 'connect to' translated action: #startWiring. aMenu addLine]. ""
self isFullOnScreen ifFalse: [aMenu add: 'move onscreen' translated action: #goHome]]. "" Preferences noviceMode ifFalse: ["" self addLayoutMenuItems: aMenu hand: evt hand. (owner notNil and: [owner isTextMorph]) ifTrue: [self addTextAnchorMenuItems: aMenu hand: evt hand]]. "" self isWorldMorph ifFalse: ["" aMenu addLine. self addToggleItemsToHaloMenu: aMenu]. "" aMenu addLine. self isWorldMorph ifFalse: [aMenu add: 'copy to paste buffer' translated action: #copyToPasteBuffer:].
- (Generator on: [:gen | self streamAllStringsAfter: nil on: gen]) in: [:gen |
- "optimized!! #allStringsAfter: can be slow for large subtrees."
- gen atEnd ifFalse: [
- aMenu add: 'copy text' translated action: #clipText]].
- (self allStringsAfter: nil) isEmpty
- ifFalse: [aMenu add: 'copy text' translated action: #clipText].
"" self addExportMenuItems: aMenu hand: evt hand. "" (Preferences noviceMode not and: [self isWorldMorph not]) ifTrue: ["" aMenu addLine. aMenu add: 'adhere to edge...' translated action: #adhereToEdge]. "" self addCustomMenuItems: aMenu hand: evt hand!
Item was changed: ----- Method: Morph>>allStringsAfter: (in category 'debug and other') -----
- allStringsAfter: aSubmorph
- allStringsAfter: aSubmorph
- "return an OrderedCollection of strings of text in my submorphs. If aSubmorph is non-nil, begin with that container."
- ^ OrderedCollection streamContents: [:stream |
- self streamAllStringsAfter: aSubmorph on: stream]!
- | list ok |
- list := OrderedCollection new.
- ok := aSubmorph isNil.
- self allMorphsDo:
- [:sub | | string |
- ok ifFalse: [ok := sub == aSubmorph]. "and do this one too"
- ok
- ifTrue:
- [(string := sub userString) ifNotNil:
- [string isString ifTrue: [list add: string] ifFalse: [list addAll: string]]]].
- ^list!
Item was added:
- ----- Method: Morph>>streamAllStringsAfter:on: (in category 'debug and other') -----
- streamAllStringsAfter: aSubmorph on: aStream
- "Stream all strings of text in my submorphs on aStream. If aSubmorph is non-nil, begin with that container."
- | ok |
- ok := aSubmorph isNil.
- self allMorphsDo: [:sub | | string |
- ok ifFalse: [ok := sub == aSubmorph].
- "and do this one too"
- ok ifTrue: [
- (string := sub userString)
- ifNotNil: [string isString
- ifTrue: [aStream nextPut: string]
- ifFalse: [aStream nextPutAll: string]]]].!
I think that we are better off following the existing patterns to improve readability. The use of Generator is surprising and maybe difficult to understand. Keep it simple and common to the surrounding interface.
Best, Marcel ________________________________ From: Thiede, Christoph christoph.thiede@student.hpi.uni-potsdam.de Sent: Friday, May 28, 2021 7:00:14 PM To: squeak-dev@lists.squeakfoundation.org squeak-dev@lists.squeakfoundation.org; marcel.taeumel@hpi.de marcel.taeumel@hpi.de Subject: Re: The Inbox: Morphic-ct.1771.mcz
Hi Marcel,
yes, I also have thought about this pattern, but I actually don't see why it would be better or why Generator would be an anti-pattern. :-) Your approach requires one more selector than my approach. In general, I think that Generators are a promising way to objectify a lazily/partially evaluatable collection.
Best, Christoph
Hi Christoph.
Thanks. I think that the expected pattern is a little bit different, though. The explicit use of Generator is unfortunate but can be easily avoided. :-)
allStringsAfter: morph do: block   "..."
allStringsAfter: morph   ^ Array streamContents: [:stream |    self allStringsAfter: morph do: [:string |      stream nextPut: string]]
hasStringsAfter: morph   self allStringsAfter: morph do: [:string | ^ true].   ^ false
Best, Marcel Am 25.05.2021 19:39:07 schrieb commits at source.squeak.org <commits at source.squeak.org>: A new version of Morphic was added to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.1771.mcz
==================== Summary ====================
Name: Morphic-ct.1771 Author: ct Time: 25 May 2021, 7:38:48.072683 pm UUID: 5a9ddaf0-a062-7047-b5b2-d2ae2da3fe15 Ancestors: Morphic-mt.1769
Fixes a bottleneck when opening a yellow button menu on a morph that contains a very large number of subsub*morphs. On not-so-fast systems, this can be reproduced using:
self systemNavigation browseAllSelect: #notNil
On faster systems, you might need to write a small toolbuilder application to reproduce the bottleneck. I have an app with >10k list items in my image which actually blocked the image for several seconds when I yellow-clicked the window.
Fixed the problem without duplicating the logic of #allStringsAfter: by using a generator.
=============== Diff against Morphic-mt.1769 ===============
Item was changed: ----- Method: Morph>>addYellowButtonMenuItemsTo:event: (in category 'menu') ----- addYellowButtonMenuItemsTo: aMenu event: evt "Populate aMenu with appropriate menu items for a yellow-button (context menu) click." aMenu defaultTarget: self. "" Preferences noviceMode ifFalse: [aMenu addStayUpItem]. "" self addModelYellowButtonItemsTo: aMenu event: evt. "" Preferences generalizedYellowButtonMenu ifFalse: [^ self]. "" aMenu addLine. aMenu add: 'inspect' translated action: #inspect. "" aMenu addLine. self world selectedObject == self ifTrue: [aMenu add: 'deselect' translated action: #removeHalo] ifFalse: [aMenu add: 'select' translated action: #addHalo]. "" (self isWorldMorph or: [self mustBeBackmost or: [self wantsToBeTopmost]]) ifFalse: ["" aMenu addLine. aMenu add: 'send to back' translated action: #goBehind. aMenu add: 'bring to front' translated action: #comeToFront. self addEmbeddingMenuItemsTo: aMenu hand: evt hand]. "" self isWorldMorph ifFalse: ["" Smalltalk at: #NCAAConnectorMorph ifPresent: [:connectorClass | aMenu addLine. aMenu add: 'connect to' translated action: #startWiring. aMenu addLine]. ""
self isFullOnScreen ifFalse: [aMenu add: 'move onscreen' translated action: #goHome]]. "" Preferences noviceMode ifFalse: ["" self addLayoutMenuItems: aMenu hand: evt hand. (owner notNil and: [owner isTextMorph]) ifTrue: [self addTextAnchorMenuItems: aMenu hand: evt hand]]. "" self isWorldMorph ifFalse: ["" aMenu addLine. self addToggleItemsToHaloMenu: aMenu]. "" aMenu addLine. self isWorldMorph ifFalse: [aMenu add: 'copy to paste buffer' translated action: #copyToPasteBuffer:].
- (Generator on: [:gen | self streamAllStringsAfter: nil on: gen]) in: [:gen |
- "optimized!! #allStringsAfter: can be slow for large subtrees."
- gen atEnd ifFalse: [
- aMenu add: 'copy text' translated action: #clipText]].
- (self allStringsAfter: nil) isEmpty
- ifFalse: [aMenu add: 'copy text' translated action: #clipText].
"" self addExportMenuItems: aMenu hand: evt hand. "" (Preferences noviceMode not and: [self isWorldMorph not]) ifTrue: ["" aMenu addLine. aMenu add: 'adhere to edge...' translated action: #adhereToEdge]. "" self addCustomMenuItems: aMenu hand: evt hand!
Item was changed: ----- Method: Morph>>allStringsAfter: (in category 'debug and other') -----
- allStringsAfter: aSubmorph
- allStringsAfter: aSubmorph
- "return an OrderedCollection of strings of text in my submorphs. If aSubmorph is non-nil, begin with that container."
- ^ OrderedCollection streamContents: [:stream |
- self streamAllStringsAfter: aSubmorph on: stream]!
- | list ok |
- list := OrderedCollection new.
- ok := aSubmorph isNil.
- self allMorphsDo:
- [:sub | | string |
- ok ifFalse: [ok := sub == aSubmorph]. "and do this one too"
- ok
- ifTrue:
- [(string := sub userString) ifNotNil:
- [string isString ifTrue: [list add: string] ifFalse: [list addAll: string]]]].
- ^list!
Item was added:
- ----- Method: Morph>>streamAllStringsAfter:on: (in category 'debug and other') -----
- streamAllStringsAfter: aSubmorph on: aStream
- "Stream all strings of text in my submorphs on aStream. If aSubmorph is non-nil, begin with that container."
- | ok |
- ok := aSubmorph isNil.
- self allMorphsDo: [:sub | | string |
- ok ifFalse: [ok := sub == aSubmorph].
- "and do this one too"
- ok ifTrue: [
- (string := sub userString)
- ifNotNil: [string isString
- ifTrue: [aStream nextPut: string]
- ifFalse: [aStream nextPutAll: string]]]].!
Hi Marcel,
please see Morphic-ct.1782. However, in a new system, I would always go for generators - treating enumeration as a first-class feature seems much more convenient to me in many cases. Btw this is the way I went in Squeak Inbox Talk, and it was a delicious way for me. :-)
Best, Christoph
--- Sent from Squeak Inbox Talk
On 2021-05-28T17:12:35+00:00, marcel.taeumel@hpi.de wrote:
I think that we are better off following the existing patterns to improve readability. The use of Generator is surprising and maybe difficult to understand. Keep it simple and common to the surrounding interface.
Best, Marcel ________________________________ From: Thiede, Christoph <christoph.thiede at student.hpi.uni-potsdam.de> Sent: Friday, May 28, 2021 7:00:14 PM To: squeak-dev at lists.squeakfoundation.org <squeak-dev at lists.squeakfoundation.org>; marcel.taeumel at hpi.de <marcel.taeumel at hpi.de> Subject: Re: The Inbox: Morphic-ct.1771.mcz
Hi Marcel,
yes, I also have thought about this pattern, but I actually don't see why it would be better or why Generator would be an anti-pattern. :-) Your approach requires one more selector than my approach. In general, I think that Generators are a promising way to objectify a lazily/partially evaluatable collection.
Best, Christoph
Hi Christoph.
Thanks. I think that the expected pattern is a little bit different, though. The explicit use of Generator is unfortunate but can be easily avoided. :-)
allStringsAfter: morph do: block   "..."
allStringsAfter: morph   ^ Array streamContents: [:stream |    self allStringsAfter: morph do: [:string |      stream nextPut: string]]
hasStringsAfter: morph   self allStringsAfter: morph do: [:string | ^ true].   ^ false
Best, Marcel Am 25.05.2021 19:39:07 schrieb commits at source.squeak.org <commits at source.squeak.org>: A new version of Morphic was added to project The Inbox: http://source.squeak.org/inbox/Morphic-ct.1771.mcz
==================== Summary ====================
Name: Morphic-ct.1771 Author: ct Time: 25 May 2021, 7:38:48.072683 pm UUID: 5a9ddaf0-a062-7047-b5b2-d2ae2da3fe15 Ancestors: Morphic-mt.1769
Fixes a bottleneck when opening a yellow button menu on a morph that contains a very large number of subsub*morphs. On not-so-fast systems, this can be reproduced using:
self systemNavigation browseAllSelect: #notNil
On faster systems, you might need to write a small toolbuilder application to reproduce the bottleneck. I have an app with >10k list items in my image which actually blocked the image for several seconds when I yellow-clicked the window.
Fixed the problem without duplicating the logic of #allStringsAfter: by using a generator.
=============== Diff against Morphic-mt.1769 ===============
Item was changed: ----- Method: Morph>>addYellowButtonMenuItemsTo:event: (in category 'menu') ----- addYellowButtonMenuItemsTo: aMenu event: evt "Populate aMenu with appropriate menu items for a yellow-button (context menu) click." aMenu defaultTarget: self. "" Preferences noviceMode ifFalse: [aMenu addStayUpItem]. "" self addModelYellowButtonItemsTo: aMenu event: evt. "" Preferences generalizedYellowButtonMenu ifFalse: [^ self]. "" aMenu addLine. aMenu add: 'inspect' translated action: #inspect. "" aMenu addLine. self world selectedObject == self ifTrue: [aMenu add: 'deselect' translated action: #removeHalo] ifFalse: [aMenu add: 'select' translated action: #addHalo]. "" (self isWorldMorph or: [self mustBeBackmost or: [self wantsToBeTopmost]]) ifFalse: ["" aMenu addLine. aMenu add: 'send to back' translated action: #goBehind. aMenu add: 'bring to front' translated action: #comeToFront. self addEmbeddingMenuItemsTo: aMenu hand: evt hand]. "" self isWorldMorph ifFalse: ["" Smalltalk at: #NCAAConnectorMorph ifPresent: [:connectorClass | aMenu addLine. aMenu add: 'connect to' translated action: #startWiring. aMenu addLine]. ""
self isFullOnScreen ifFalse: [aMenu add: 'move onscreen' translated action: #goHome]]. "" Preferences noviceMode ifFalse: ["" self addLayoutMenuItems: aMenu hand: evt hand. (owner notNil and: [owner isTextMorph]) ifTrue: [self addTextAnchorMenuItems: aMenu hand: evt hand]]. "" self isWorldMorph ifFalse: ["" aMenu addLine. self addToggleItemsToHaloMenu: aMenu]. "" aMenu addLine. self isWorldMorph ifFalse: [aMenu add: 'copy to paste buffer' translated action: #copyToPasteBuffer:].
- (Generator on: [:gen | self streamAllStringsAfter: nil on: gen]) in: [:gen |
- "optimized!! #allStringsAfter: can be slow for large subtrees."
- gen atEnd ifFalse: [
- aMenu add: 'copy text' translated action: #clipText]].
- (self allStringsAfter: nil) isEmpty
- ifFalse: [aMenu add: 'copy text' translated action: #clipText].
"" self addExportMenuItems: aMenu hand: evt hand. "" (Preferences noviceMode not and: [self isWorldMorph not]) ifTrue: ["" aMenu addLine. aMenu add: 'adhere to edge...' translated action: #adhereToEdge]. "" self addCustomMenuItems: aMenu hand: evt hand!
Item was changed: ----- Method: Morph>>allStringsAfter: (in category 'debug and other') -----
- allStringsAfter: aSubmorph
- allStringsAfter: aSubmorph
- "return an OrderedCollection of strings of text in my submorphs. If aSubmorph is non-nil, begin with that container."
- ^ OrderedCollection streamContents: [:stream |
- self streamAllStringsAfter: aSubmorph on: stream]!
- | list ok |
- list := OrderedCollection new.
- ok := aSubmorph isNil.
- self allMorphsDo:
- [:sub | | string |
- ok ifFalse: [ok := sub == aSubmorph]. "and do this one too"
- ok
- ifTrue:
- [(string := sub userString) ifNotNil:
- [string isString ifTrue: [list add: string] ifFalse: [list addAll: string]]]].
- ^list!
Item was added:
- ----- Method: Morph>>streamAllStringsAfter:on: (in category 'debug and other') -----
- streamAllStringsAfter: aSubmorph on: aStream
- "Stream all strings of text in my submorphs on aStream. If aSubmorph is non-nil, begin with that container."
- | ok |
- ok := aSubmorph isNil.
- self allMorphsDo: [:sub | | string |
- ok ifFalse: [ok := sub == aSubmorph].
- "and do this one too"
- ok ifTrue: [
- (string := sub userString)
- ifNotNil: [string isString
- ifTrue: [aStream nextPut: string]
- ifFalse: [aStream nextPutAll: string]]]].!
squeak-dev@lists.squeakfoundation.org