'From Squeak3.7gamma of ''17 July 2004'' [latest update: #5976] on 26 July 2004 at 10:41:11 am'! "Change Set: SecondClickTimeoutFix-nk Date: 26 July 2004 Author: Ned Konz Fixes two problems in MouseClickState: - down/up/down/wait would generate an incorrect doubleClick. - down/up/down/move would not generate startDrag Also corrects and clarifies the MouseClickState-related comments in HandMorph. Also corrects the balloonText instructions in DoubleClickExample. " ! !DoubleClickExample methodsFor: 'accessing' stamp: 'nk 7/26/2004 10:38'! balloonText ^ 'Double-click on me to change my color; single-click on me to change border color; hold mouse down within me and then move it to grow (if I''m red) or shrink (if I''m blue).' translated ! ! !HandMorph methodsFor: 'double click support' stamp: 'nk 7/26/2004 10:29'! waitForClicksOrDrag: aMorph event: evt "Wait for mouse button and movement events, informing aMorph about events interesting to it via callbacks. This message is typically sent to the Hand by aMorph when it first receives a mouse-down event. The callback methods invoked on aMorph (which are passed a copy of evt) are: #click: sent when the mouse button goes up within doubleClickTime. #doubleClick: sent when the mouse goes up, down, and up again all within DoubleClickTime. #doubleClickTimeout: sent when the mouse does not have a doubleClick within DoubleClickTime. #startDrag: sent when the mouse moves more than 10 pixels from evt's position within DoubleClickTime. Note that mouseMove: and mouseUp: events are not sent to aMorph until it becomes the mouse focus, which is typically done by aMorph in its click:, doubleClick:, or drag: methods." ^self waitForClicksOrDrag: aMorph event: evt selectors: #( #click: #doubleClick: #doubleClickTimeout: #startDrag:) threshold: 10 ! ! !HandMorph methodsFor: 'double click support' stamp: 'nk 7/26/2004 10:32'! waitForClicksOrDrag: aMorph event: evt selectors: clickAndDragSelectors threshold: threshold "Wait for mouse button and movement events, informing aMorph about events interesting to it via callbacks. This message is typically sent to the Hand by aMorph when it first receives a mouse-down event. The callback methods, named in clickAndDragSelectors and passed a copy of evt, are: 1 (click) sent when the mouse button goes up within doubleClickTime. 2 (doubleClick) sent when the mouse goes up, down, and up again all within DoubleClickTime. 3 (doubleClickTimeout) sent when the mouse does not have a doubleClick within DoubleClickTime. 4 (startDrag) sent when the mouse moves more than threshold pixels from evt's position within DoubleClickTime. Note that mouseMove: and mouseUp: events are not sent to aMorph until it becomes the mouse focus, which is typically done by aMorph in its click:, doubleClick:, or drag: methods." mouseClickState _ MouseClickState new client: aMorph click: clickAndDragSelectors first dblClick: clickAndDragSelectors second dblClickTime: DoubleClickTime dblClickTimeout: clickAndDragSelectors third drag: clickAndDragSelectors fourth threshold: threshold event: evt. ! ! !MouseClickState methodsFor: 'event handling' stamp: 'nk 7/26/2004 10:21'! handleEvent: evt from: aHand "Process the given mouse event to detect a click, double-click, or drag. Return true if the event should be processed by the sender, false if it shouldn't. NOTE: This method heavily relies on getting *all* mouse button events." | localEvt timedOut isDrag | timedOut _ (evt timeStamp - firstClickTime) > dblClickTime. localEvt _ evt transformedBy: (clickClient transformedFrom: aHand owner). isDrag _ (localEvt position - firstClickDown position) r > dragThreshold. clickState == #firstClickDown ifTrue: [ "Careful here - if we had a slow cycle we may have a timedOut mouseUp event" (timedOut and:[localEvt isMouseUp not]) ifTrue:[ "timeout before #mouseUp -> keep waiting for drag if requested" clickState _ #firstClickTimedOut. dragSelector ifNil:[ aHand resetClickState. self doubleClickTimeout; click "***"]. ^true]. localEvt isMouseUp ifTrue:[ (timedOut or:[dblClickSelector isNil]) ifTrue:[ self click. aHand resetClickState. ^true]. "Otherwise transfer to #firstClickUp" firstClickUp _ evt copy. clickState _ #firstClickUp. "If timedOut or the client's not interested in dbl clicks get outta here" self click. aHand handleEvent: firstClickUp. ^false]. isDrag ifTrue:["drag start" self doubleClickTimeout. "***" aHand resetClickState. dragSelector "If no drag selector send #click instead" ifNil: [self click] ifNotNil: [self drag: firstClickDown]. ^true]. ^false]. clickState == #firstClickTimedOut ifTrue:[ localEvt isMouseUp ifTrue:["neither drag nor double click" aHand resetClickState. self doubleClickTimeout; click. "***" ^true]. isDrag ifTrue:["drag start" aHand resetClickState. self doubleClickTimeout; drag: firstClickDown. "***" ^true]. ^false]. clickState = #firstClickUp ifTrue:[ (timedOut) ifTrue:[ "timed out after mouseUp - signal timeout and pass the event" aHand resetClickState. self doubleClickTimeout. "***" ^true]. localEvt isMouseDown ifTrue:["double click" clickState _ #secondClickDown. ^false]]. clickState == #secondClickDown ifTrue: [ timedOut ifTrue:[ "timed out after second mouseDown - pass event after signaling timeout" aHand resetClickState. self doubleClickTimeout. "***" ^true]. isDrag ifTrue: ["drag start" self doubleClickTimeout. "***" aHand resetClickState. dragSelector "If no drag selector send #click instead" ifNil: [self click] ifNotNil: [self drag: firstClickDown]. ^true]. localEvt isMouseUp ifTrue: ["double click" aHand resetClickState. self doubleClick. ^false] ]. ^true ! ! !MouseClickState methodsFor: 'as yet unclassified' stamp: 'nk 7/26/2004 09:13'! printOn: aStream super printOn: aStream. aStream nextPut: $[; print: clickState; nextPut: $] ! !