<div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000;text-align: left" dir="ltr">
<img id="bc40476b-1053-4f66-82c1-20ed501db98c" src="cid:94efd291-fc7a-4b8c-af47-720794ff5704" width="586" height="331"></img><br><div class="mb_sig"></div>
<blockquote class="history_container" type="cite" style="border-left-style: solid;border-width: 1px;margin-top: 20px;margin-left: 0px;padding-left: 10px;min-width: 500px">
<p style="color: #AAAAAA; margin-top: 10px;">Am 18.04.2021 19:01:02 schrieb commits@source.squeak.org <commits@source.squeak.org>:</p><div style="font-family:Arial,Helvetica,sans-serif">Marcel Taeumel uploaded a new version of Morphic to project The Trunk:<br>http://source.squeak.org/trunk/Morphic-mt.1755.mcz<br><br>==================== Summary ====================<br><br>Name: Morphic-mt.1755<br>Author: mt<br>Time: 18 April 2021, 7:00:43.878254 pm<br>UUID: e5705780-2988-a54e-b6c7-21b4194fcd5c<br>Ancestors: Morphic-mt.1754, Morphic-ct.1659<br><br>Fix our two menu-invocating buttons to act on mouse-down and actually look like menus: (1) menu button in system window and (2) change-set button in world-main-docking-bar.<br><br>Merges Morphic-ct.1659. Thanks Christoph (ct) for pointing out this issue about menu invocation through buttons. See http://forum.world.st/The-Inbox-Morphic-ct-1659-mcz-tp5116728.html<br><br>By example, this commit also adds a menu to the change-set button in the docking bar. This menu lists the latest method and class changes.<br><br>To make this work, the following things got addressed:<br>- Fixes DockingBarUpdatingItemMorph, which missed several changes from DockingBarItemMorph. (Interesting specialization challenge...)<br>- Let menus #rubberBandCells to allow for changing menu item's widths.<br>- Adds query about latest changes to #listChangesOn:. (Feel free to improve this. Maybe add preference for number of elements?)<br><br>Complements (and depends on) System-mt.1228 and Tools-mt.1042.<br><br>=============== Diff against Morphic-mt.1754 ===============<br><br>Item was changed:<br> ----- Method: DockingBarMorph>>addUpdatingItem: (in category 'construction') -----<br> addUpdatingItem: aBlock<br> | item |<br> item := DockingBarUpdatingItemMorph new.<br> aBlock value: item.<br>+ item subMenu ifNotNil: [:menu |<br>+ "Docking bar and protruding menu should appear visually merged."<br>+ menu morphicLayerNumber: self morphicLayerNumber + 1].<br> self addMorphBack: item!<br><br>Item was changed:<br> ----- Method: DockingBarMorph>>ensureSelectedItem: (in category 'events') -----<br> ensureSelectedItem: evt<br> <br> self selectedItem ifNil: [<br> self <br> selectItem: (<br> self submorphs <br>+ detect: [ :each | each isMenuItemMorph ] <br>- detect: [ :each | each isKindOf: DockingBarItemMorph ] <br> ifNone: [ ^self ]) <br> event: evt ]!<br><br>Item was changed:<br> ----- Method: DockingBarMorph>>filterEvent:for: (in category 'events-processing') -----<br> filterEvent: aKeyboardEvent for: anObject<br> "Provide keyboard shortcuts."<br> <br> | index itemToSelect |<br> <br> aKeyboardEvent controlKeyPressed<br> ifFalse: [^ aKeyboardEvent].<br> <br> aKeyboardEvent isKeystroke<br> ifFalse: [^ aKeyboardEvent].<br> <br> "Search field."<br> aKeyboardEvent keyCharacter = $0<br> ifTrue: [<br> self searchBarMorph ifNotNil: [ :morph |<br> morph model activate: aKeyboardEvent in: morph ].<br> ^ aKeyboardEvent ignore "hit!!"].<br> <br> "Select menu items."<br> (aKeyboardEvent keyValue <br> between: $1 asciiValue <br> and: $9 asciiValue)<br> ifFalse: [^ aKeyboardEvent]. <br> <br> index := aKeyboardEvent keyValue - $1 asciiValue + 1.<br> itemToSelect := (self submorphs select: [ :each | <br>+ each isMenuItemMorph ]) <br>- each isKindOf: DockingBarItemMorph ]) <br> at: index <br> ifAbsent: [^ aKeyboardEvent].<br> <br> self activate: aKeyboardEvent.<br> self <br> selectItem: itemToSelect<br> event: aKeyboardEvent.<br> <br> ^ aKeyboardEvent ignore "hit!!"!<br><br>Item was changed:<br> ----- Method: DockingBarMorph>>moveSelectionDown:event: (in category 'control') -----<br> moveSelectionDown: direction event: evt<br> "Move the current selection up or down by one, presumably under keyboard control.<br> direction = +/-1"<br> <br> | index |<br> index := (submorphs indexOf: selectedItem ifAbsent: [1-direction]) + direction.<br> submorphs do: "Ensure finite"<br> [:unused | | m |<br> m := submorphs atWrap: index.<br>+ (m isMenuItemMorph and: [m isEnabled]) ifTrue:<br>- ((m isKindOf: DockingBarItemMorph) and: [m isEnabled]) ifTrue:<br> [^ self selectItem: m event: evt].<br> "Keep looking for an enabled item"<br> index := index + direction sign].<br> ^ self selectItem: nil event: evt!<br><br>Item was added:<br>+ ----- Method: DockingBarUpdatingItemMorph>>adjacentTo (in category 'selecting') -----<br>+ adjacentTo<br>+ <br>+ | roundedCornersOffset verticalOffset |<br>+ roundedCornersOffset := MenuMorph roundedMenuCorners<br>+ ifTrue: [Morph preferredCornerRadius negated]<br>+ ifFalse: [0].<br>+ verticalOffset := 2.<br>+ <br>+ owner isFloating<br>+ ifTrue: [^ {self bounds bottomLeft + (roundedCornersOffset @ verticalOffset)}].<br>+ owner isAdheringToTop<br>+ ifTrue: [^ {self bounds bottomLeft + (roundedCornersOffset @ verticalOffset)}].<br>+ owner isAdheringToLeft<br>+ ifTrue: [^ {self bounds topRight + (roundedCornersOffset @ verticalOffset)}].<br>+ owner isAdheringToBottom<br>+ ifTrue: [^ {self bounds topLeft + (roundedCornersOffset @ verticalOffset)}].<br>+ owner isAdheringToRight<br>+ ifTrue: [^ {self bounds topLeft + (roundedCornersOffset @ verticalOffset negated)}].<br>+ ^ {self bounds bottomLeft + (roundedCornersOffset @ 5)}!<br><br>Item was added:<br>+ ----- Method: DockingBarUpdatingItemMorph>>createSubmenu (in category 'private') -----<br>+ createSubmenu<br>+ <br>+ ^DockingBarMenuMorph new!<br><br>Item was added:<br>+ ----- Method: DockingBarUpdatingItemMorph>>createUpdatingSubmenu (in category 'private') -----<br>+ createUpdatingSubmenu<br>+ <br>+ ^DockingBarUpdatingMenuMorph new!<br><br>Item was changed:<br>+ ----- Method: DockingBarUpdatingItemMorph>>decorateOwner (in category 'world') -----<br>- ----- Method: DockingBarUpdatingItemMorph>>decorateOwner (in category 'as yet unclassified') -----<br> decorateOwner<br> <br> "Ignore."!<br><br>Item was added:<br>+ ----- Method: DockingBarUpdatingItemMorph>>drawIconOn: (in category 'drawing') -----<br>+ drawIconOn: aCanvas <br>+ <br>+ | pos |<br>+ self hasIcon ifTrue: [<br>+ | iconForm | <br>+ iconForm := self iconForm.<br>+ <br>+ pos := (contents<br>+ ifEmpty: [self left + (self width - iconForm width // 2)]<br>+ ifNotEmpty: [self left])<br>+ @ (self top + (self height - iconForm height // 2)).<br>+ <br>+ aCanvas<br>+ translucentImage: iconForm <br>+ at: pos].!<br><br>Item was added:<br>+ ----- Method: DockingBarUpdatingItemMorph>>drawLabelOn: (in category 'drawing') -----<br>+ drawLabelOn: aCanvas <br>+ <br>+ | stringBounds | <br>+ self contents ifEmpty: [^ self].<br>+ <br>+ stringBounds := bounds.<br>+ <br>+ self hasIcon ifTrue: [<br>+ stringBounds := stringBounds left: stringBounds left + self iconForm width + 2 ].<br>+ <br>+ "Vertical centering."<br>+ stringBounds := stringBounds top: stringBounds top + stringBounds bottom - self fontToUse height // 2.<br>+ "Horizontal centering."<br>+ stringBounds := stringBounds left: stringBounds left + (stringBounds width - (self fontToUse widthOfString: contents) // 2) abs.<br>+ <br>+ aCanvas<br>+ drawString: contents<br>+ in: stringBounds<br>+ font: self fontToUse<br>+ color: self colorToUse.!<br><br>Item was added:<br>+ ----- Method: DockingBarUpdatingItemMorph>>drawSubMenuMarkerOn: (in category 'drawing') -----<br>+ drawSubMenuMarkerOn: aCanvas <br>+ "Ignore."!<br><br>Item was added:<br>+ ----- Method: DockingBarUpdatingItemMorph>>mouseDown: (in category 'events') -----<br>+ mouseDown: evt<br>+ "Handle a mouse down event. Menu items get activated when the mouse is over them."<br>+ <br>+ (evt shiftPressed and:[self wantsKeyboardFocusOnShiftClick]) ifTrue: [ ^super mouseDown: evt ]. "enable label editing" <br>+ isSelected<br>+ ifTrue: [<br>+ owner selectItem: nil event: evt. ]<br>+ ifFalse: [<br>+ owner activate: evt. "Redirect to menu for valid transitions"<br>+ owner selectItem: self event: evt. ]<br>+ !<br><br>Item was changed:<br>+ ----- Method: DockingBarUpdatingItemMorph>>mouseEnter: (in category 'events') -----<br>- ----- Method: DockingBarUpdatingItemMorph>>mouseEnter: (in category 'as yet unclassified') -----<br> mouseEnter: evt<br> "Do not hover docking bar items directory. Mouse-down required. But if you already see a submenu, support hovering."<br> <br> owner selectedItem ifNotNil: [owner selectItem: self event: evt]!<br><br>Item was added:<br>+ ----- Method: DockingBarUpdatingItemMorph>>mouseUp: (in category 'events') -----<br>+ mouseUp: evt<br>+ "Handle a mouse up event. Menu items get activated when the mouse is over them. Do nothing if we're not in a 'valid menu transition', meaning that the current hand focus must be aimed at the owning menu."<br>+ <br>+ evt hand mouseFocus == owner ifFalse: [ ^self ].<br>+ self contentString ifNotNil: [<br>+ self contents: self contentString withMarkers: true inverse: true.<br>+ self refreshWorld.<br>+ (Delay forMilliseconds: 200) wait ].!<br><br>Item was added:<br>+ ----- Method: DockingBarUpdatingItemMorph>>select: (in category 'selecting') -----<br>+ select: evt<br>+ <br>+ super select: evt.<br>+ subMenu ifNotNil: [<br>+ evt hand newKeyboardFocus: subMenu ]!<br><br>Item was added:<br>+ ----- Method: DockingBarUpdatingItemMorph>>wantsKeyboardFocusOnShiftClick (in category 'events') -----<br>+ wantsKeyboardFocusOnShiftClick<br>+ "set this preference to false to prevent user editing of docking bar menu items"<br>+ ^Preferences valueOfPreference: #allowMenubarItemEditing ifAbsent: [false]!<br><br>Item was added:<br>+ ----- Method: DockingBarUpdatingMenuMorph>>morphicLayerNumber: (in category 'update') -----<br>+ morphicLayerNumber: n<br>+ <br>+ super morphicLayerNumber: n.<br>+ !<br><br>Item was changed:<br> ----- Method: MenuMorph>>initialize (in category 'initialization') -----<br> initialize<br> super initialize.<br> <br> self setDefaultParameters.<br> <br> self changeTableLayout.<br> self listDirection: #topToBottom.<br> self hResizing: #shrinkWrap.<br> self vResizing: #shrinkWrap.<br>+ self rubberBandCells: true.<br> self disableLayout: true.<br> self morphicLayerNumber: self class menuLayer.<br> defaultTarget := nil.<br> selectedItem := nil.<br> stayUp := false.<br> popUpOwner := nil.!<br><br>Item was changed:<br> ----- Method: SystemWindow>>createMenuBox (in category 'initialization') -----<br> createMenuBox<br> ^ (self createBox: self class menuBoxImage)<br> actionSelector: #offerWindowMenu;<br>+ setBalloonText: 'window menu' translated;<br>+ actWhen: #buttonDown;<br>+ yourself!<br>- setBalloonText: 'window menu' translated!<br><br>Item was changed:<br>+ ----- Method: TheWorldMainDockingBar>>browseChanges (in category 'submenu - changes') -----<br>- ----- Method: TheWorldMainDockingBar>>browseChanges (in category 'right side') -----<br> browseChanges<br> <br> ChangeSorter open.!<br><br>Item was changed:<br>+ ----- Method: TheWorldMainDockingBar>>browseChangesLabel (in category 'submenu - changes') -----<br>- ----- Method: TheWorldMainDockingBar>>browseChangesLabel (in category 'right side') -----<br> browseChangesLabel<br> "The project name is the same as the current change set."<br> <br> ^ Project current name!<br><br>Item was added:<br>+ ----- Method: TheWorldMainDockingBar>>changesMenuOn: (in category 'submenu - changes') -----<br>+ changesMenuOn: aDockingBar<br>+ <br>+ aDockingBar addUpdatingItem: [:item |<br>+ item<br>+ help: 'Browse this project''s changes' translated;<br>+ wordingProvider: self<br>+ wordingSelector: #browseChangesLabel;<br>+ subMenuUpdater: self<br>+ selector: #listChangesOn:].!<br><br>Item was changed:<br> ----- Method: TheWorldMainDockingBar>>fillDockingBar: (in category 'construction') -----<br> fillDockingBar: aDockingBar <br> "Private - fill the given docking bar"<br> <br> self menusOn: aDockingBar.<br> aDockingBar addSpacer.<br>+ self changesMenuOn: aDockingBar.<br>- self projectNameOn: aDockingBar.<br> aDockingBar addSpacer.<br> self rightSideOn: aDockingBar.<br> aDockingBar<br> setProperty: #mainDockingBarTimeStamp <br> toValue: self class timeStamp.!<br><br>Item was added:<br>+ ----- Method: TheWorldMainDockingBar>>listChangesOn: (in category 'submenu - changes') -----<br>+ listChangesOn: menu<br>+ <br>+ | latestMethodChanges latestClassChanges|<br>+ latestMethodChanges := (Array streamContents: [:s |<br>+ ChangeSet current changedMethodsDo: [:method :changeType :dateAndTime :category |<br>+ s nextPut: { dateAndTime. method. changeType. category }]])<br>+ sorted: [:a :b | a first >= b first].<br>+ <br>+ 1 to: (10 min: latestMethodChanges size) do: [:index | | spec method |<br>+ spec := latestMethodChanges at: index.<br>+ method := spec second.<br>+ menu addItem: [:item |<br>+ item<br>+ contents: ('{1} {2} \{{3}\} \{{4}\}' format: {method methodClass. method selector. spec fourth. method methodClass category}) ;<br>+ target: ToolSet;<br>+ balloonText: spec third asString;<br>+ icon: ((#(remove addedThenRemoved) includes: spec third) ifTrue: [MenuIcons smallDeleteIcon] ifFalse: [<br>+ spec third = #add ifTrue: [MenuIcons smallNewIcon] ifFalse: [MenuIcons blankIcon]]);<br>+ selector: (method isInstalled ifTrue: [#browseMethod:] ifFalse: [#browseMethodVersion:]);<br>+ arguments: {method}]].<br>+ <br>+ latestClassChanges := (Array streamContents: [:s |<br>+ ChangeSet current changedClassesDo: [:class :changeTypes :dateAndTime :category |<br>+ "We are not interested in classes whose method's did only change."<br>+ changeTypes ifNotEmpty: [s nextPut: { dateAndTime. class. changeTypes. category }]]])<br>+ sorted: [:a :b | a first >= b first].<br>+ <br>+ latestClassChanges ifNotEmpty: [menu addLine].<br>+ 1 to: (10 min: latestClassChanges size) do: [:index | | spec class |<br>+ spec := latestClassChanges at: index.<br>+ class := spec second.<br>+ menu addItem: [:item |<br>+ item<br>+ contents: ('{1} \{{2}\}' format: {class name. spec fourth }) ;<br>+ target: ToolSet;<br>+ balloonText: (spec third sorted joinSeparatedBy: Character space);<br>+ icon: ((spec third includesAnyOf: #(remove addedThenRemoved))<br>+ ifTrue: [MenuIcons smallDeleteIcon]<br>+ ifFalse: [<br>+ (spec third includes: #add)<br>+ ifTrue: [MenuIcons smallNewIcon]<br>+ ifFalse: [MenuIcons blankIcon]]);<br>+ selector: ((spec third includes: #remove) ifTrue: [#inspect:] ifFalse: [#browseClass:]);<br>+ arguments: {class}]].<br>+ <br>+ menu addLine; addItem: [:item |<br>+ item<br>+ contents: 'Browse current change set...' translated;<br>+ target: self;<br>+ selector: #browseChanges].!<br><br>Item was removed:<br>- ----- Method: TheWorldMainDockingBar>>projectNameOn: (in category 'right side') -----<br>- projectNameOn: aDockingBar<br>- <br>- aDockingBar addUpdatingItem: [:item |<br>- item<br>- help: 'Browse this project''s changes';<br>- target: self;<br>- selector: #browseChanges;<br>- wordingProvider: self<br>- wordingSelector: #browseChangesLabel].!<br><br>Item was changed:<br>+ (PackageInfo named: 'Morphic') postscript: 'TheWorldMainDockingBar updateInstances.'!<br>- (PackageInfo named: 'Morphic') postscript: 'Transcript showln: ''[NOTICE] There is a new preference called "Interactive print-it". Please check your preference browser to choose the preferred value.'''!<br><br><br></div></blockquote></div>