Hello Marcel,
could you please give some more background information about the method #translateTo: which seems to have been introduced with this change? I loaded BabySRE-hjh.44 (http://wiki.squeak.org/squeak/2551) into Squeak6.0alpha #17970 (current trunk) and got the error AConnectorSRE (a morph) does not understand #translateTo: --Hannes ........................................................................................................................... translateTo: messages in current trunk: ............................................................................................................................ UserEvent>>translateTo: point position := point. DropEvent>>translateTo: point position := point. MorphicEvent>>translateTo: point "empty method body" On Mon, 20 Jun 2016 15:14:05.567 0000, [hidden email] <[hidden email]> wrote: > Marcel Taeumel uploaded a new version of Morphic to project The Trunk: > http://source.squeak.org/trunk/Morphic-mt.1182.mcz > > ==================== Summary ==================== > > Name: Morphic-mt.1182 > Author: mt > Time: 20 June 2016, 5:13:55.570796 pm > UUID: 825d8e52-1878-af49-9f7a-437b23e68d8c > Ancestors: Morphic-mt.1181 > > Moves implementation of focus event dispatching from various places into > MorphicEventDispatcher. This will ensure consistency in the future because > MorphicEventDispatcher encode the tree iteration with capturing and > bubbling. Doing a focus event is just a shortcut into the tree. TextMorphs > use that. Pop-up menus use that. Modal dialogs use that. > > Fixes missing coordinate transformations when capturing and bubbling for > focus events. > > Simplify focus-related code in MenuMorph, UserDialogBoxMorph, and > DockingBarMorph. > > At the time of writing, there seems to be no need anymore for Morph >> > #handleFocusEvent:. Still, keep it for compatibility to other projects. > > =============== Diff against Morphic-mt.1181 =============== > > Item was removed: > - ----- Method: DockingBarMorph>>handleFocusEvent: (in category > 'events-processing') ----- > - handleFocusEvent: evt > - "Handle focus events. Valid menu transitions are determined based on the > menu currently holding the focus after the mouse went down on one of its > children." > - > - | result filteredEvent | > - (evt isMouse and:[ evt isMouseUp ]) ifTrue:[^ evt]. > - > - result := self processEvent: evt. > - filteredEvent := result == #rejected ifTrue: [evt] ifFalse: [result]. > - > - "Need to handle keyboard input if we have the focus." > - filteredEvent isKeyboard ifTrue: [^ super handleFocusEvent: > filteredEvent]. > - > - "We need to handle button clicks outside and transitions to local popUps > so throw away everything else" > - (filteredEvent isMouseOver or:[filteredEvent isMouse not]) > ifTrue:[^filteredEvent]. > - "What remains are mouse buttons and moves" > - filteredEvent isMove ifFalse:[^super handleFocusEvent: filteredEvent]. > "handle clicks outside by regular means" > - "Now it's getting tricky. On #mouseMove we might transfer control to > *either* the currently active submenu or the pop up owner, if any. Since the > active sub menu is always displayed upfront check it first." > - selectedItem ifNotNil:[(selectedItem activateSubmenu: filteredEvent) > ifTrue:[^filteredEvent]]. > - ! > > Item was added: > + ----- Method: DockingBarMorph>>mouseMove: (in category > 'events-processing') ----- > + mouseMove: evt > + "We might transfer control to *either* the currently active submenu or > the pop up owner, if any. Since the active sub menu is always displayed > upfront check it first." > + > + selectedItem ifNotNil:[selectedItem activateSubmenu: evt].! > > Item was added: > + ----- Method: DockingBarMorph>>processFocusEvent:using: (in category > 'events-processing') ----- > + processFocusEvent: evt using: dispatcher > + > + ^ dispatcher dispatchFocusEventFully: evt with: self! > > Item was added: > + ----- Method: DockingBarMorph>>wantsEveryMouseMove (in category > 'events-processing') ----- > + wantsEveryMouseMove > + ^ true! > > Item was changed: > ----- Method: HandMorph>>sendFocusEvent:to:clear: (in category 'private > events') ----- > sendFocusEvent: anEvent to: focusHolder clear: aBlock > "Send the event to the morph currently holding the focus" > + > | result w | > w := focusHolder world ifNil:[aBlock value. ^ anEvent]. > w becomeActiveDuring:[ > ActiveHand := self. > ActiveEvent := anEvent. > + result := focusHolder processFocusEvent: anEvent. > - result := focusHolder handleFocusEvent: > - (anEvent transformedBy: (focusHolder transformedFrom: self)). > ]. > + ^ result == #rejected ifTrue: [anEvent] ifFalse: [result "filtered > event"]! > - ^result == #rejected ifTrue: [anEvent] ifFalse: [result "filtered > event"]! > > Item was removed: > - ----- Method: MenuMorph>>handleFocusEvent: (in category 'events') ----- > - handleFocusEvent: evt > - "Handle focus events. Valid menu transitions are determined based on the > menu currently holding the focus after the mouse went down on one of its > children." > - | result filteredEvent | > - result := self processEvent: evt. > - filteredEvent := result == #rejected ifTrue: [evt] ifFalse: [result]. > - > - "Need to handle keyboard input if we have the focus." > - filteredEvent isKeyboard ifTrue: [^ super handleFocusEvent: > filteredEvent]. > - > - "We need to handle button clicks outside and transitions to local popUps > so throw away everything else" > - (filteredEvent isMouseOver or:[filteredEvent isMouse not]) > ifTrue:[^filteredEvent]. > - "What remains are mouse buttons and moves" > - filteredEvent isMove ifFalse:[^super handleFocusEvent: filteredEvent]. > "handle clicks outside by regular means" > - "Now it's getting tricky. On #mouseMove we might transfer control to > *either* the currently active submenu or the pop up owner, if any. Since the > active sub menu is always displayed upfront check it first." > - selectedItem ifNotNil: [ > - (selectedItem activateSubmenu: filteredEvent) > - ifTrue: [ ^filteredEvent ] > - ifFalse: [ > - (self containsPoint: filteredEvent position) ifFalse: [ > - self selectItem: nil event: filteredEvent ] ] ]. > - "Note: The following does not traverse upwards but it's the best I can do > for now" > - popUpOwner ifNotNil:[(popUpOwner activateOwnerMenu: filteredEvent) > ifTrue:[^filteredEvent]]. > - ^ filteredEvent! > > Item was removed: > - ----- Method: MenuMorph>>handleMouseMove: (in category 'events') ----- > - handleMouseMove: evt > - " If the mouse moves over an item not selected, we try to set it as > selected. > - If this happens depends on that the current selected item wants to > release > - its selection. " > - > - self selectedItem ifNil: [ ^super handleMouseMove: evt ]. > - (self selectedItem containsPoint: evt position) ifTrue: [ ^super > handleMouseMove: evt ]. > - self > - selectItem: ( > - self items > - detect: [ :each | each containsPoint: evt position ] > - ifNone: [ nil ]) > - event: evt. > - super handleMouseMove: evt! > > Item was added: > + ----- Method: MenuMorph>>mouseMove: (in category 'events') ----- > + mouseMove: evt > + " If the mouse moves over an item not selected, we try to set it as > selected. > + If this happens depends on that the current selected item wants to > release > + its selection. " > + > + self selectedItem ifNil: [ ^ self ]. > + (self selectedItem containsPoint: evt position) ifTrue: [ ^ self ]. > + self > + selectItem: ( > + self items > + detect: [ :each | each containsPoint: evt position ] > + ifNone: [ nil ]) > + event: evt. > + > + "Transfer control to *either* the currently active submenu or the pop up > owner, if any. Since the active sub menu is always displayed upfront check > it first." > + selectedItem ifNotNil: [ > + (selectedItem activateSubmenu: evt) > + ifTrue: [ ^self ] > + ifFalse: [ > + (self containsPoint: evt position) ifFalse: [ > + self selectItem: nil event: evt ] ] ]. > + > + "Note: The following does not traverse upwards but it's the best I can do > for now" > + popUpOwner ifNotNil:[popUpOwner activateOwnerMenu: evt]! > > Item was added: > + ----- Method: MenuMorph>>processFocusEvent:using: (in category 'events') > ----- > + processFocusEvent: evt using: dispatcher > + > + ^ dispatcher dispatchFocusEventFully: evt with: self! > > Item was added: > + ----- Method: MenuMorph>>wantsEveryMouseMove (in category 'events') ----- > + wantsEveryMouseMove > + ^ true! > > Item was changed: > ----- Method: Morph>>handleFocusEvent: (in category 'events-processing') > ----- > handleFocusEvent: anEvent > + "Handle the given event. This message is sent if the receiver currently > has the focus and is therefore receiving events directly from some hand. > However, it might already have been handled due to overrides in > #processFocusEvent:using:. We might want to get rid of this call-back in the > future..." > - "Handle the given event. This message is sent if the receiver currently > has the focus and is therefore receiving events directly from some hand. > > + ^ anEvent wasHandled > + ifTrue: [anEvent] > + ifFalse: [self handleEvent: anEvent]! > - 1) Event bubbling. Do event bubbling known from MorphicEventDispatcher by > calling #handleEvent: also on all owners. > - 2) Event capture filters. Walk along the owner chain in reverse order and > apply capture filters as known from MorphicEventDispatcher. > - > - If you want to overwrite this in a subclass (for example to implement > modal dialogs) ensure to call super instead if #handleEvent: directly." > - > - | filteredEvent | > - filteredEvent := anEvent. > - > - "TODO: Add a check to ensure that our event dispatcher is actually of > kind MorphicEventDispatcher?!! We do copy its behavior though... like self > defaultEventDispatcher class == MorphicEventDispatcher? Or #isKindOf:? > Anyway, the outermost morph determines the event dispatcher. See HandMorph >>> #sendEvent:focus:clear: and PasteUpMorph >> #processEvent:." > - > - "Event capturing. Filters only because the capturing phase was bypassed > by using the keyboard/mouse focus." > - self withAllOwners reverseDo: [:morph | "reverse order to comply with > default MorphEventDispatcher" > - morph == anEvent hand ifFalse: [ "Fixes drag-and-drop bug." > - filteredEvent := morph sendFilterEventCapture: filteredEvent for: > morph. > - filteredEvent wasIgnored ifTrue: [^ filteredEvent]]]. > - > - "Event bubbling. Filters are processed in #handleEvent:." > - self withAllOwnersDo: [:morph | > - morph == anEvent hand ifFalse: [ "Fixes drag-and-drop bug." > - filteredEvent := morph handleEvent: filteredEvent. > - filteredEvent wasIgnored ifTrue: [^ filteredEvent]]]. > - > - ^ filteredEvent! > > Item was added: > + ----- Method: Morph>>processFocusEvent: (in category 'events-processing') > ----- > + processFocusEvent: anEvent > + > + ^self processFocusEvent: anEvent using: self defaultEventDispatcher! > > Item was added: > + ----- Method: Morph>>processFocusEvent:using: (in category > 'events-processing') ----- > + processFocusEvent: anEvent using: defaultDispatcher > + "Event dispatching shortcut." > + > + ^ defaultDispatcher dispatchFocusEvent: anEvent with: self! > > Item was changed: > + ----- Method: MorphicEventDispatcher>>dispatchEvent:toSubmorphsOf: (in > category 'support') ----- > - ----- Method: MorphicEventDispatcher>>dispatchEvent:toSubmorphsOf: (in > category 'private') ----- > dispatchEvent: anEvent toSubmorphsOf: aMorph > "Dispatch the given event to the submorphs of the given morph. For > coordinate transformations, work only with copies. Either return the given > event or a copy of any filtered event to employ immutability to some extent. > --- PRIVATE!!" > > | localEvent filteredEvent | > aMorph submorphsDo: [:child | > localEvent := anEvent transformedBy: (child transformedFrom: aMorph). > filteredEvent := child > processEvent: localEvent > using: self. "use same dispatcher" > filteredEvent == #rejected ifFalse: [ "some event or #rejected symbol" > self flag: #overlappingChildren. "mt: We cannot give two overlapping > siblings the chance to handle the event!!" > + ^ self nextFromOriginal: anEvent local: localEvent filtered: > filteredEvent]]. > - filteredEvent == localEvent > - ifTrue: [ > - localEvent wasHandled ifTrue: [anEvent copyHandlerState: > localEvent]. > - anEvent wasIgnored: localEvent wasIgnored. > - ^ anEvent] > - ifFalse: [ > - filteredEvent := filteredEvent copy. > - filteredEvent translateTo: anEvent position. "restore to > untransformed coordinates" > - filteredEvent wasHandled ifFalse: [filteredEvent copyHandlerState: > anEvent]. "restore handler if needed" > - ^ filteredEvent]]]. > > ^ #rejected! > > Item was changed: > + ----- Method: MorphicEventDispatcher>>dispatchEvent:withHandler:withMorph: > (in category 'support') ----- > - ----- Method: MorphicEventDispatcher>>dispatchEvent:withHandler:withMorph: > (in category 'private') ----- > dispatchEvent: anEvent withHandler: aHandler withMorph: aMorph > "Perform the actual event dispatch. Use the given object as handler. Ask > submorphs first to handle the event. Then bubble up. Stop if ignored. Note > that event rejection and event filters are two separete concepts. Filters > come from the outside. Rejection is a morph's decision. > > * The top-most chain of visible, unlocked morphs containing the event > position will get a chance to handle the event. > * When travelling up, the prospective handler is always executed. The > handler needs to check if the event was handled before as well as checking > if somebody else's handler has been installed. > * If another handler has been installed but the event was not handled it > means that somebody up in the hierarchy wants to handle the event." > > | result filteredEvent | > > result := self dispatchEvent: anEvent toSubmorphsOf: aMorph. > > result == #rejected "Anybody?" > ifFalse: [filteredEvent := result] > ifTrue: [ > "My submorphs did not want it. Do I want it anyway? It's about locked > children..." > (aMorph containsPoint: anEvent position event: anEvent) > ifFalse: [^ #rejected]. > filteredEvent := anEvent "there was no filtering, only basic > rejects"]. > > "Receiver is in the top-most unlocked, visible chain." > (aHandler notNil and: [filteredEvent wasIgnored not]) > ifTrue: [filteredEvent := aHandler handleEvent: filteredEvent]. > > ^ filteredEvent! > > Item was added: > + ----- Method: MorphicEventDispatcher>>dispatchFocusEvent:with: (in > category 'focus events') ----- > + dispatchFocusEvent: anEventWithGlobalPosition with: focusMorph > + "Dispatch the given event to the given morph. Simulate capturing phase, > handle the event, then do bubbling." > + > + | currentEvent | > + "1) Capturing phase." > + currentEvent := self doCapturingForFocusEvent: anEventWithGlobalPosition > with: focusMorph. > + currentEvent == #rejected ifTrue: [^ #rejected]. > + currentEvent wasIgnored ifTrue: [^ currentEvent]. > + > + "2) No sub-tree processing here. Use #dispatchFocusEventFully:with: if > you want that, too." > + > + "3) Let the focus morph handle the event." > + currentEvent := self doHandlingForFocusEvent: currentEvent with: > focusMorph. > + currentEvent wasIgnored ifTrue: [^ currentEvent]. > + > + "4) Bubbling phase" > + ^ self doBubblingForFocusEvent: currentEvent with: focusMorph! > > Item was added: > + ----- Method: MorphicEventDispatcher>>dispatchFocusEventFully:with: (in > category 'focus events') ----- > + dispatchFocusEventFully: anEventWithGlobalPosition with: focusMorph > + "Dispatch the given event to the given morph. Do capturing, processing in > sub-tree, and bubbling." > + > + | currentEvent | > + "1) Capturing phase." > + currentEvent := self doCapturingForFocusEvent: anEventWithGlobalPosition > with: focusMorph. > + currentEvent == #rejected ifTrue: [^ #rejected]. > + currentEvent wasIgnored ifTrue: [^ currentEvent]. > + > + "2) Sub-tree processing." > + currentEvent := self doProcessingForFocusEvent: currentEvent with: > focusMorph. > + currentEvent wasIgnored ifTrue: [^ currentEvent]. > + > + "3) Let the focus morph handle the event. Usually no effect because > previous sub-tree processing involved the focus morph already -- at least in > the bubbling phase. Skip it?" > + currentEvent := self doHandlingForFocusEvent: currentEvent with: > focusMorph. > + currentEvent wasIgnored ifTrue: [^ currentEvent]. > + > + "4) Bubbling phase." > + ^ self doBubblingForFocusEvent: currentEvent with: focusMorph! > > Item was added: > + ----- Method: MorphicEventDispatcher>>doBubblingForFocusEvent:with: (in > category 'support') ----- > + doBubblingForFocusEvent: anEvent with: focusMorph > + "Simulate real event bubbling up to the focused morph's outermost owner. > Applies event bubble filters via Morph >> #handleEvent:. Watch out for > coordinate transformations and some globals (ActiveWorld, ...)." > + > + | currentEvent filteredEvent localEvent referenceMorph | > + currentEvent := anEvent. > + referenceMorph := anEvent hand. > + > + focusMorph allOwnersDo: [:ownerMorph | > + ownerMorph == anEvent hand ifFalse: [ "Never bubble up to the hand morph > but only up to the world." > + localEvent := currentEvent transformedBy: (ownerMorph transformedFrom: > referenceMorph). > + filteredEvent := ownerMorph handleEvent: localEvent. > + currentEvent := self nextFromOriginal: currentEvent local: localEvent > filtered: filteredEvent. > + currentEvent wasIgnored ifTrue: [^ currentEvent]]]. > + > + ^ currentEvent! > > Item was added: > + ----- Method: MorphicEventDispatcher>>doCapturingForFocusEvent:with: (in > category 'support') ----- > + doCapturingForFocusEvent: anEvent with: focusMorph > + "Simulate real event capturing down to the focused morph. Apply event > capture filters. Watch out for coordinate transformations. Keep the > filter-ignore-reject order like in Morph >> #processEvent:using:." > + > + | currentEvent filteredEvent localEvent referenceMorph | > + currentEvent := anEvent. > + referenceMorph := anEvent hand. > + > + "Event capturing. Filters only because the capturing phase was bypassed > by using the keyboard/mouse focus." > + focusMorph withAllOwners reverseDo: [:ownerMorph | "reverse order to > comply with regular dispatching" > + ownerMorph == anEvent hand ifFalse: [ "Never dispatch the hand morph. It > already did so." > + localEvent := currentEvent transformedBy: (ownerMorph transformedFrom: > referenceMorph). > + > + filteredEvent := ownerMorph sendFilterEventCapture: localEvent for: > ownerMorph. > + > + "Ignoring has higher priority but the reject-check must be with local > event coodinates." > + (filteredEvent wasIgnored not and: [ownerMorph rejectsEvent: > filteredEvent]) > + ifTrue: [^ #rejected]. > + > + currentEvent := self nextFromOriginal: currentEvent local: localEvent > filtered: filteredEvent. > + currentEvent wasIgnored ifTrue: [^ currentEvent]]]. > + > + ^ currentEvent! > > Item was added: > + ----- Method: MorphicEventDispatcher>>doHandlingForFocusEvent:with: (in > category 'support') ----- > + doHandlingForFocusEvent: currentEvent with: focusMorph > + > + | localEvent filteredEvent | > + localEvent := currentEvent transformedBy: (focusMorph transformedFrom: > currentEvent hand). > + filteredEvent := focusMorph handleFocusEvent: localEvent. > + ^ self nextFromOriginal: currentEvent local: localEvent filtered: > filteredEvent.! > > Item was added: > + ----- Method: MorphicEventDispatcher>>doProcessingForFocusEvent:with: (in > category 'support') ----- > + doProcessingForFocusEvent: currentEvent with: focusMorph > + "Sub-tree processing (including capturing from focus morph down to > something and bubbling up back to focus morph). Never reject in the end." > + > + | localEvent filteredEvent | > + localEvent := currentEvent transformedBy: (focusMorph transformedFrom: > currentEvent hand). > + filteredEvent := focusMorph processEvent: localEvent using: self. > + ^ filteredEvent == #rejected > + ifTrue: [currentEvent] "Can happen if you click, e.g., outside the > bounds of the focus morph" > + ifFalse: [self nextFromOriginal: currentEvent local: localEvent > filtered: filteredEvent]! > > Item was added: > + ----- Method: MorphicEventDispatcher>>nextFromOriginal:local:filtered: (in > category 'support') ----- > + nextFromOriginal: originalEvent local: localEvent filtered: filteredEvent > + "Take the filtered event if different but always keep the original > coordinates." > + > + filteredEvent == localEvent > + ifTrue: [ "Use original event but keep track of ignored flag." > + localEvent wasHandled ifTrue: [originalEvent copyHandlerState: > localEvent]. > + originalEvent wasIgnored: localEvent wasIgnored. > + ^ originalEvent] > + ifFalse: [ "There was an event transformation. Copy, revert coordinates, > keep handler state." > + | result | > + result := filteredEvent copy. "Never mutate position without copying. > MouseClickState etc. will break otherwise." > + result translateTo: originalEvent position. "restore to untransformed > coordinates" > + result wasHandled ifFalse: [result copyHandlerState: originalEvent]. > + ^ result]. > + ! > > Item was removed: > - ----- Method: UserDialogBoxMorph>>handleFocusEvent: (in category > 'constructing') ----- > - handleFocusEvent: evt > - "Handle focus events. Valid menu transitions are determined based on the > menu currently holding the focus after the mouse went down on one of its > children. Need to handle keyboard input if we have the focus." > - > - | result filteredEvent | > - result := self processEvent: evt. > - filteredEvent := result == #rejected ifTrue: [evt] ifFalse: [result]. > - > - ^ super handleFocusEvent: filteredEvent! > > Item was added: > + ----- Method: UserDialogBoxMorph>>processFocusEvent:using: (in category > 'events') ----- > + processFocusEvent: evt using: dispatcher > + > + ^ dispatcher dispatchFocusEventFully: evt with: self! > > > |
Hi Hannes, the message #translateTo: is a simpler version of #transformedBy:, which was added back in 2000. Basically, these are helper methods to cope with local coordinate systems in TransformMorphs. It is only used in MorphicEventDispatcher. The term "translate" means geometry like in Rectangle. No morph should ever receive this message, only MorphicEvent (sub-)instances. I suppose there are some issues in BabySRE considering overrides of: Morph >> #handleEvent: Morph >> #handleFocusEvent: Morph >> #processEvent: Morph >> #processEvent:using: Morph >> #processFocusEvent: Morph >> #processFocusEvent:using: All these methods must return an event object, not "self" (or a morph). Best, Marcel
|
Free forum by Nabble | Edit this page |