<div dir="ltr"><div>Hi,<br></div><div>I found the issues debugging TextOnCurve not working.</div><div>Often the submorph would be outside the bounds of the owner. <br></div><div>And it would also bug on drawing.</div><div><br></div><div>I'm pretty sure this used to work.<br></div><div><br></div><div>Cheers,</div><div>Karl</div><div><br></div><div><br></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr">On Mon, Dec 31, 2018 at 8:05 PM Chris Muller <<a href="mailto:asqueaker@gmail.com">asqueaker@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Those are two things that should work.  I'll take a look.<br>
<br>
On Sun, Dec 30, 2018 at 5:45 PM karl ramberg <<a href="mailto:karlramberg@gmail.com" target="_blank">karlramberg@gmail.com</a>> wrote:<br>
><br>
> I have a couple of more issues with this change:<br>
><br>
> I can't get a halo on a submorph with drawing error.<br>
> It is also hard to get a halo on a submorph that is outside of the bounds of the owner morph.<br>
><br>
> Cheers,<br>
> Karl<br>
><br>
><br>
><br>
> On Tue, Sep 4, 2018 at 4:00 AM Chris Muller <<a href="mailto:asqueaker@gmail.com" target="_blank">asqueaker@gmail.com</a>> wrote:<br>
>><br>
>> Fixed by Morphic-cmm.1462.<br>
>> On Sun, Sep 2, 2018 at 5:00 AM karl ramberg <<a href="mailto:karlramberg@gmail.com" target="_blank">karlramberg@gmail.com</a>> wrote:<br>
>> ><br>
>> > This change breaks blue clicks for rotated morphs in  PasteUpMorph>>tryInvokeHalo:<br>
>> > It does not bring up a halo anymore.<br>
>> > The variable stack is just #().<br>
>> ><br>
>> > stack := (self morphsAt: aUserInputEvent position unlocked: true) select:<br>
>> >                [ : each | each wantsHaloFromClick or: [ each handlesMouseDown: aUserInputEvent ] ].<br>
>> ><br>
>> > Best,<br>
>> > Karl<br>
>> ><br>
>> > On Sat, Jun 23, 2018 at 11:25 PM <<a href="mailto:commits@source.squeak.org" target="_blank">commits@source.squeak.org</a>> wrote:<br>
>> >><br>
>> >> Chris Muller uploaded a new version of Morphic to project The Trunk:<br>
>> >> <a href="http://source.squeak.org/trunk/Morphic-cmm.1454.mcz" rel="noreferrer" target="_blank">http://source.squeak.org/trunk/Morphic-cmm.1454.mcz</a><br>
>> >><br>
>> >> ==================== Summary ====================<br>
>> >><br>
>> >> Name: Morphic-cmm.1454<br>
>> >> Author: cmm<br>
>> >> Time: 23 June 2018, 4:23:51.324266 pm<br>
>> >> UUID: 7bd5a7a9-4493-4cf4-849f-be6d8f8bb991<br>
>> >> Ancestors: Morphic-hjh.1453<br>
>> >><br>
>> >> - Fix ability of border styles of veryDeepCopied Morphs to be independently set.<br>
>> >> - Fix dispatch regression for Morphs that leave world based on mouseLeave.<br>
>> >> - Fix three UI-gesture inconsistencies related to invoking halos, depending on the position of existing halos:<br>
>> >>         1) halo activation was sometimes on mouseUp instead of mouseDown,<br>
>> >>         2) blue move/resize gestures sometimes operated on the background window instead of the foreground, and,<br>
>> >>         3) even with the (Shift) modifier key, it was sometimes selecting the outermost instead of the innermost.<br>
>> >> All three are fixed while reverting the increased dependence on #transferHalo:, putting us closer to considerations like multiple, independent, and custom halos.<br>
>> >> - Restore splitter bar thicknesses from 2 back to 4 pixels.<br>
>> >> - Restore blue-click functionality of splitters when Smart Splitters is off.<br>
>> >> - Let SystemWindows dismiss halos with any button, mouse or keyboard.<br>
>> >><br>
>> >> =============== Diff against Morphic-hjh.1453 ===============<br>
>> >><br>
>> >> Item was added:<br>
>> >> + ----- Method: ComplexBorder>>veryDeepInner: (in category 'copying') -----<br>
>> >> + veryDeepInner: aDeepCopier<br>
>> >> +       super veryDeepInner: aDeepCopier.<br>
>> >> +       style := style veryDeepCopyWith: aDeepCopier.<br>
>> >> +       colors := colors veryDeepCopyWith: aDeepCopier.<br>
>> >> +       lineStyles := lineStyles veryDeepCopyWith: aDeepCopier.!<br>
>> >><br>
>> >> Item was changed:<br>
>> >>   ----- Method: Editor class>>dumbbellCursor (in category 'preferences') -----<br>
>> >>   dumbbellCursor<br>
>> >> +       <preference: 'Dumbbell Text Cursor'<br>
>> >> -       <preference: 'Dumbbell-shaped Text Cursor'<br>
>> >>                 category: 'Morphic'<br>
>> >> +               description: 'When enabled, the text cursor assumes the shape of a dumbbell, otherwise a vertical bar.'<br>
>> >> -               description: 'When true, the text cursor assumes the shape of a dumbbell, otherwise a vertical bar..'<br>
>> >>                 type: #Boolean><br>
>> >>         ^ DumbbellCursor ifNil: [ false ]!<br>
>> >><br>
>> >> Item was changed:<br>
>> >>   ----- Method: MorphicEventDispatcher>>dispatchFocusEventAllOver:with: (in category 'focus events') -----<br>
>> >>   dispatchFocusEventAllOver: evt with: focusMorph<br>
>> >>         "Like a full event dispatch BUT adds regular dispatch if the focus morph did nothing with the event. This is useful for letting the focusMorph's siblings handle the events instead. Take halo invocation as an example. See senders of me."<br>
>> >><br>
>> >>         | result hand mouseFocus |<br>
>> >>         result := self dispatchFocusEventFully: evt with: focusMorph.<br>
>> >><br>
>> >>         result == #rejected ifTrue: [^ result].<br>
>> >>         result wasIgnored ifTrue: [^ result].<br>
>> >>         result wasHandled ifTrue: [^ result].<br>
>> >> +       focusMorph world ifNil: [ ^ result ].<br>
>> >><br>
>> >>         hand := evt hand.<br>
>> >>         mouseFocus := hand mouseFocus.<br>
>> >><br>
>> >>         [<br>
>> >>                 "Avoid re-dispatching the event to the focus morph. See Morph >> #rejectsEvent:."<br>
>> >>                 focusMorph lock.<br>
>> >><br>
>> >>                 "Handle side effect for mouse-enter and mouse-leave events."<br>
>> >>                 self flag: #hacky. "mt: Maybe we find a better way to synthesize enter/leave events in the future."<br>
>> >>                 hand newMouseFocus: nil.<br>
>> >>                 hand mouseOverHandler processMouseOver: hand lastEvent.<br>
>> >><br>
>> >>                 "Give the morph's world a chance to normally dispatch the event."<br>
>> >> +               ^ focusMorph world ifNotNil: [ : world | world processEvent: evt using: self]<br>
>> >> -               ^ focusMorph world processEvent: evt using: self<br>
>> >>         ] ensure: [<br>
>> >>                 focusMorph unlock.<br>
>> >>                 evt hand newMouseFocus: mouseFocus].!<br>
>> >><br>
>> >> Item was changed:<br>
>> >>   ----- Method: PasteUpMorph>>tryInvokeHalo: (in category 'events-processing') -----<br>
>> >> + tryInvokeHalo: aUserInputEvent<br>
>> >> +       "Invoke halos around the top-most world container at aUserInputEvent's #position.  If it was already halo'd, zero-in on its next inward component morph at that position.  Holding Shift during the click reverses this traversal order."<br>
>> >> +       | stack innermost haloTarget |<br>
>> >> +       Preferences noviceMode ifTrue: [ ^ self ].<br>
>> >> +       Morph haloForAll ifFalse: [ ^ self ].<br>
>> >> +       "the stack is the top-most morph to bottom-most."<br>
>> >> +       stack := (self morphsAt: aUserInputEvent position unlocked: true) select:<br>
>> >> +               [ : each | each wantsHaloFromClick or: [ each handlesMouseDown: aUserInputEvent ] ].<br>
>> >> +       innermost := aUserInputEvent hand halo<br>
>> >> +               ifNil: [ stack first ]<br>
>> >> +               ifNotNil:<br>
>> >> +                       [ : existingHalo | stack allButFirst "existingHalo is first on the stack, not a target"<br>
>> >> +                               detect: [ : each | each owner == self ]<br>
>> >> +                               ifFound:<br>
>> >> +                                       [ : worldContainer | "Is existingHalo's target part of the same worldContainer as the morph clicked?"<br>
>> >> +                                       (existingHalo target withAllOwners includes: worldContainer)<br>
>> >> +                                               ifTrue: [ "same hierarchy, let #transferHalo: continue to handle it for now."  ^ self ]<br>
>> >> +                                               ifFalse:<br>
>> >> +                                                       [ "different hierarchy, remove + add."<br>
>> >> +                                                       aUserInputEvent hand removeHalo.<br>
>> >> +                                                       aUserInputEvent shiftPressed<br>
>> >> +                                                               ifTrue: [ stack second "first is still the just removed halo" ]<br>
>> >> +                                                               ifFalse: [ worldContainer ] ] ]<br>
>> >> +                               ifNone: [ "Shouldn't get here, but defensive code."  self ] ].<br>
>> >> +       "If modifier key is pressed, start at innermost (the target), otherwise the outermost (direct child of the world (self))."<br>
>> >> +       haloTarget  := aUserInputEvent shiftPressed<br>
>> >> +               ifTrue: [ innermost ]<br>
>> >> +               ifFalse: [ innermost == self ifTrue: [innermost] ifFalse: [(innermost withAllOwners copyWithout: self) last] ].<br>
>> >> +       haloTarget wantsHaloFromClick ifFalse: [ "haloTarget has its own event handler." ^ self ].<br>
>> >> +       "Now that we have the haloTarget, show the halo."<br>
>> >> +       aUserInputEvent hand<br>
>> >> +               newMouseFocus: haloTarget<br>
>> >> +               event: aUserInputEvent.<br>
>> >> +       haloTarget invokeHaloOrMove: aUserInputEvent.<br>
>> >> +       "aUserInputEvent has been consumed, don't let it cause any further side-effects."<br>
>> >> +       aUserInputEvent ignore!<br>
>> >> - tryInvokeHalo: anEvent<br>
>> >> -<br>
>> >> -       | innerMost target |<br>
>> >> -       anEvent hand halo ifNotNil: [^ self "No invocation needed. Halo will handle transfer itself."].<br>
>> >> -       Preferences noviceMode ifTrue: [^ self "No halo in novice mode."].<br>
>> >> -       Morph haloForAll ifFalse: [^ self].<br>
>> >> -<br>
>> >> -       innerMost := (self morphsAt: anEvent position unlocked: true) first.<br>
>> >> -<br>
>> >> -       "1) Try to use innermost morph but skip all the ones that do not want to show a halo along the owner chain."<br>
>> >> -       target := innerMost.<br>
>> >> -       [target isNil or: [target wantsHaloFromClick]]<br>
>> >> -               whileFalse: [target := target owner].<br>
>> >> -       target ifNil: [^ self].<br>
>> >> -<br>
>> >> -       "2) Without a modifier, which is normal, find the outermost container for that inner morph."<br>
>> >> -       (innerMost == self or: [anEvent shiftPressed]) ifFalse: [<br>
>> >> -               | previousTargets |<br>
>> >> -               previousTargets := OrderedCollection new.<br>
>> >> -               [target notNil and: [target owner ~~ self]] whileTrue: [<br>
>> >> -                       previousTargets add: target.<br>
>> >> -                       target := target owner].<br>
>> >> -               target ifNil: [^ self].<br>
>> >> -               [previousTargets isEmpty or: [target wantsHaloFromClick]] whileFalse: [<br>
>> >> -                       target := previousTargets removeLast].<br>
>> >> -               target wantsHaloFromClick ifFalse: [^ self]].<br>
>> >> -<br>
>> >> -       "3) Now that we have the target, show the halo. Abort event dispatching, too, to avoid confusion."<br>
>> >> -       anEvent hand newMouseFocus: target event: anEvent.<br>
>> >> -       target invokeHaloOrMove: anEvent.<br>
>> >> -       anEvent ignore.!<br>
>> >><br>
>> >> Item was changed:<br>
>> >>   ----- Method: ProportionalSplitterMorph>>balanceOffsets (in category 'layout') -----<br>
>> >>   balanceOffsets<br>
>> >><br>
>> >> +       | fdx fdy |<br>
>> >> +<br>
>> >>         (self hasProperty: #fullDelta) ifFalse: [^ self].<br>
>> >><br>
>> >> +       fdx := (self valueOfProperty: #fullDelta) x.<br>
>> >> +       fdy := (self valueOfProperty: #fullDelta) y.<br>
>> >> +<br>
>> >>         self layoutFrame hasFixedHeight ifTrue: [<br>
>> >>                 | otop obot ctop cbot topf |<br>
>> >><br>
>> >>                 otop := (owner submorphs detect: [:m |<br>
>> >>                                         m layoutFrame topFraction isZero] ifNone: [^ self]) in: [:tm |<br>
>> >>                                                 tm top - (tm layoutFrame topOffset ifNil: [0])].<br>
>> >><br>
>> >>                 obot := (owner submorphs detect: [:m |<br>
>> >>                                         m layoutFrame bottomFraction = 1] ifNone: [^ self]) in: [:tm |<br>
>> >>                                                 tm bottom - (tm layoutFrame bottomOffset ifNil: [0])].<br>
>> >><br>
>> >>                 ctop := (self layoutFrame topFraction * (obot - otop)) rounded<br>
>> >>                                         + otop + (self layoutFrame topOffset ifNil: [0]).<br>
>> >>                 cbot := (self layoutFrame bottomFraction * (obot - otop)) rounded<br>
>> >>                                         + otop + (self layoutFrame bottomOffset ifNil: [0]).<br>
>> >><br>
>> >>                 topf := self layoutFrame topFraction.<br>
>> >>                 self layoutFrame topFraction:  ((ctop + cbot) * 0.5 - otop) / (obot - otop) asFloat.<br>
>> >>                 self layoutFrame bottomFraction: self layoutFrame topFraction.<br>
>> >> +               self layoutFrame topOffset: self layoutFrame topOffset - fdy.<br>
>> >> +               self layoutFrame bottomOffset: self layoutFrame bottomOffset - fdy.<br>
>> >> -               self layoutFrame topOffset: ctop -<br>
>> >> -                       (self layoutFrame topFraction * (obot - otop) + otop) truncated.<br>
>> >> -               self layoutFrame bottomOffset: cbot -<br>
>> >> -                       (self layoutFrame bottomFraction * (obot - otop) + otop) rounded.<br>
>> >><br>
>> >>                 (leftOrTop copy union: rightOrBottom) do: [:m |<br>
>> >>                         (m layoutFrame topFraction closeTo: topf) ifTrue: [<br>
>> >>                                 m layoutFrame topFraction: self layoutFrame topFraction.<br>
>> >> +                               m layoutFrame topOffset: m layoutFrame topOffset - fdy].<br>
>> >> -                               m layoutFrame topOffset:<br>
>> >> -                                       m layoutFrame topOffset - (self valueOfProperty: #fullDelta) y].<br>
>> >>                         (m layoutFrame bottomFraction closeTo: topf) ifTrue: [<br>
>> >>                                 m layoutFrame bottomFraction: self layoutFrame topFraction.<br>
>> >> +                               m layoutFrame bottomOffset: m layoutFrame bottomOffset - fdy]]] .<br>
>> >> -                               m layoutFrame bottomOffset:<br>
>> >> -                                       m layoutFrame bottomOffset - (self valueOfProperty: #fullDelta) y.]]] .<br>
>> >><br>
>> >>         self layoutFrame hasFixedWidth ifTrue: [<br>
>> >>                 | oleft oright cleft cright leftf |<br>
>> >><br>
>> >>                 oleft := (owner submorphs detect: [:m |<br>
>> >>                         m layoutFrame leftFraction isZero] ifNone: [^ self]) in: [:tm |<br>
>> >>                                 tm left - (tm layoutFrame leftOffset ifNil: [0])].<br>
>> >><br>
>> >>                 oright := (owner submorphs detect: [:m |<br>
>> >>                         m layoutFrame rightFraction = 1] ifNone: [^ self]) in: [:tm |<br>
>> >>                                 tm right - (tm layoutFrame rightOffset ifNil: [0])].<br>
>> >><br>
>> >>                 cleft := (self layoutFrame leftFraction * (oright - oleft)) rounded<br>
>> >>                                         + oleft + (self layoutFrame leftOffset ifNil: [0]).<br>
>> >>                 cright := (self layoutFrame rightFraction * (oright - oleft)) rounded<br>
>> >>                                         + oleft + (self layoutFrame rightOffset ifNil: [0]).<br>
>> >><br>
>> >>                 leftf := self layoutFrame leftFraction.<br>
>> >>                 self layoutFrame leftFraction: ((cleft + cright) * 0.5 - oleft) / (oright - oleft) asFloat.<br>
>> >>                 self layoutFrame rightFraction: self layoutFrame leftFraction.<br>
>> >><br>
>> >> -               self layoutFrame leftOffset: cleft -<br>
>> >> -                       (self layoutFrame leftFraction * (oright - oleft) + oleft) truncated.<br>
>> >> -               self layoutFrame rightOffset: cright -<br>
>> >> -                       (self layoutFrame rightFraction * (oright - oleft) + oleft) rounded.<br>
>> >><br>
>> >> +               self layoutFrame leftOffset: self layoutFrame leftOffset - fdx.<br>
>> >> +               self layoutFrame rightOffset: self layoutFrame rightOffset - fdx.<br>
>> >> +<br>
>> >>                 (leftOrTop copy union: rightOrBottom) do: [:m |<br>
>> >>                         (m layoutFrame leftFraction closeTo: leftf) ifTrue: [<br>
>> >>                                 m layoutFrame leftFraction: self layoutFrame leftFraction.<br>
>> >> +                               m layoutFrame leftOffset: m layoutFrame leftOffset - fdx].<br>
>> >> -                               m layoutFrame leftOffset:<br>
>> >> -                                       m layoutFrame leftOffset - (self valueOfProperty: #fullDelta) x].<br>
>> >>                         (m layoutFrame rightFraction closeTo: leftf) ifTrue: [<br>
>> >>                                 m layoutFrame rightFraction: self layoutFrame leftFraction.<br>
>> >> +                               m layoutFrame rightOffset:      m layoutFrame rightOffset - fdx.]]] .<br>
>> >> +<br>
>> >> -                               m layoutFrame rightOffset:<br>
>> >> -                                       m layoutFrame rightOffset - (self valueOfProperty: #fullDelta) x.]]] .<br>
>> >> -<br>
>> >>         self removeProperty: #fullDelta.<br>
>> >>         owner layoutChanged<br>
>> >>   !<br>
>> >><br>
>> >> Item was added:<br>
>> >> + ----- Method: ProportionalSplitterMorph>>stopStepping (in category 'events') -----<br>
>> >> + stopStepping<br>
>> >> +       super stopStepping.<br>
>> >> +       (self class smartVerticalSplitters or: [ self class smartHorizontalSplitters ]) ifFalse: [ self balanceOffsets ]!<br>
>> >><br>
>> >> Item was changed:<br>
>> >>   ----- Method: SimpleHaloMorph>>transferHalo: (in category 'pop up') -----<br>
>> >>   transferHalo: event<br>
>> >> +       "Transfer the halo to the next likely recipient"<br>
>> >> -       "Transfer the halo to the next likely recipient. Switch between siblings if overlapping."<br>
>> >><br>
>> >> -       (self target world morphsAt: event position) allButFirst "... the halo itself"<br>
>> >> -               detect: [:morph |<br>
>> >> -                       "Sibling found?"<br>
>> >> -                       (morph owner == self target owner<br>
>> >> -                               and: [morph ~~ self target])<br>
>> >> -                                       ifTrue: [<br>
>> >> -                                               ^ morph invokeHaloOrMove: event].<br>
>> >> -                       "No sibling possible anymore?"<br>
>> >> -                       morph == self target].<br>
>> >> -<br>
>> >>         self target<br>
>> >>                 transferHalo: (event transformedBy: (self target transformedFrom: self))<br>
>> >>                 from: self target.!<br>
>> >><br>
>> >> Item was changed:<br>
>> >>   ----- Method: SystemWindow>>filterEvent:for: (in category 'events') -----<br>
>> >>   filterEvent: aKeyboardEvent for: anObject<br>
>> >>         "Provide keyboard shortcuts."<br>
>> >> +<br>
>> >> -<br>
>> >>         aKeyboardEvent isKeystroke<br>
>> >>                 ifFalse: [^ aKeyboardEvent].<br>
>> >> +<br>
>> >> +       aKeyboardEvent hand halo ifNotNil: [ : halo | halo target isSystemWindow ifTrue: [ aKeyboardEvent hand removeHalo ] ].<br>
>> >><br>
>> >>         aKeyboardEvent commandKeyPressed ifTrue: [<br>
>> >> +               aKeyboardEvent keyCharacter caseOf: {<br>
>> >> -               aKeyboardEvent keyCharacter caseOf: {<br>
>> >>                         [$\] -> [self class sendTopWindowToBack].<br>
>> >>                         [Character escape] -> [self class deleteTopWindow].<br>
>> >>                         [$/] -> [self class bringWindowUnderHandToFront].<br>
>> >>                 } otherwise: [^ aKeyboardEvent "no hit"].<br>
>> >>                 ^ aKeyboardEvent ignore "hit!!"].<br>
>> >><br>
>> >>         aKeyboardEvent controlKeyPressed ifTrue: [<br>
>> >>                 aKeyboardEvent keyCharacter caseOf: {<br>
>> >>                         [Character escape] -> [self world findWindow: aKeyboardEvent].<br>
>> >>                 } otherwise: [^ aKeyboardEvent "no hit"].<br>
>> >>                 ^ aKeyboardEvent ignore "hit!!"].<br>
>> >><br>
>> >>         ^ aKeyboardEvent "no hit"!<br>
>> >><br>
>> >><br>
>> ><br>
>><br>
><br>
<br>
</blockquote></div>