{ import: sdl } { import: MiniCairo } { import: Views } { import: Views-drawing } { import: Views-properties } { import: Views-events } { import: Views-scrolling } { import: Views-layout } { import: Colour } { import: Shape } { import: Event } { import: EventHandler } TestCase : Object () TestCase assert: result equals: expected [ result = expected ifTrue: [^ 'success' putln]. ('failure: expected = ', expected printString, ' result = ', result printString) putln. ] TestCase testView [ | view translated world | 'TestCase >> testView' putln. view := (Rectangle origin: 10, 10 extent: 20, 30) shapedView transformView. translated := view translateBy: 10, 10. self assert: translated bounds origin equals: 20, 20. world := WorldView new. world add: translated. translated translateBy: 10, 10. self assert: translated bounds origin equals: 30, 30. world add: view. self assert: view equals: translated. self assert: (view translateBy: 10, 10) container equals: world contents. ] TestCase testTransform [ | t | t := Transform2D withIdentity translatedBy: 20, 10. self assert: (10, 10 transformedBy: t) equals: 30, 20. t translatedBy: 10, 10. self assert: (0, 0 transformedBy: t) equals: 20, 10. t translateBy: 10, 10. self assert: (0, 0 transformedBy: t) equals: 30, 20. ] WorldView : ShapedView (eventHandler damage) WorldView new [ self := super new. eventHandler := EventHandler withWorld: self. ] WorldView dispatchEvent: anEvent [ | view | anEvent ifFalse: [^self]. anEvent handler: eventHandler. eventHandler handleEvent: anEvent. ] WorldView pushEventHandler: anEventHandler [ anEventHandler previous: eventHandler. eventHandler := anEventHandler. ] WorldView popEventHandler: anEventHandler [ eventHandler == anEventHandler ifFalse: [self error: 'non-LIFO event handlers']. eventHandler := eventHandler previous. ] WorldView globalToLocal: aPointOrShape [ ^aPointOrShape ] WorldView damaged: aRectangle [ damage := damage = nil ifTrue: [aRectangle] ifFalse: [damage union: aRectangle]. ] WorldView forceDamageToScreenOn: aCanvas [ damage ifNil: [^self]. damage := (damage intersect: self bounds) expanded outsetBy: 2,2. aCanvas setClipRectangle: damage. self drawOn: aCanvas in: damage. " aCanvas setSourceR: 0 G: 1 B: 0; rectangle: damage; setStrokeWidth: 1; stroke." damage := nil. ] WorldView layoutChanged: source [] DraggingEventHandler pointerUpEvent :anEvent [ self deactivate. focus layoutChanged: focus. ^anEvent handled: self ] ScrollingView layoutChanged: source [ source printString putln. source bounds printString putln. self scrollTo: source bounds. source damaged. ] EventHandler quitEvent :anEvent [ ^world handleEvent: anEvent ] CompositeView quitEvent :anEvent [ ^nil ] ComposableView quitEvent :anEvent [ ^nil ] [ TestCase testView. TestCase testTransform. ] [ | extent sdl cairo r v1 v2 world isRunning pane | extent := 300, 200. sdl := SDL new. sdl setVideoMode : extent x : extent y : 32 : 0. cairo := Cairo createImageSurfaceCreateForData: sdl pixels : extent. v1 := (0, 0 extent: 30, 30) shapedView. v1 fillColour: (Colour withR: 0.6 G: 0.6 B: 0.9). v1 := v1 transformView. v1 translateBy: 20, 20. v1 propertyAt: #pointerDownEvent put: [:v :event | event handler beginDragging: v from: event]. v2 := (0, 0 extent: 30, 30) shapedView. v2 fillColour: (Colour withR: 0.9 G: 0.6 B: 0.6). v2 := v2 transformView. v2 translateBy: 200, 300. v2 propertyAt: #pointerDownEvent put: [:v :event | event handler beginDragging: v from: event]. pane := (0, 0 extent: extent x - 10, extent y) scrollingView. pane fillColour: (Colour withR: 0.8 G: 0.8 B: 0.9). pane add: v1. pane add: v2. pane := pane withVerticalScrollBar. world := WorldView withShape: (0, 0 extent: extent). world fillColour: Colour white. world add: pane. world propertyAt: #quitEvent put: [:v :event | isRunning := false ]. world drawOn: cairo in: world bounds. isRunning := true. [isRunning] whileTrue: [ | event key | world forceDamageToScreenOn: cairo. sdl flip. event := sdl waitEvent. (event isKindOf: Event) ifTrue: [ event localPosition: event position. world dispatchEvent: event. ]]. SDL quit. ]