.
"
COPYRIGHT (c) 1992 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
Object subclass:#Controller
instanceVariableNames:'model view sensor'
classVariableNames:''
poolDictionaries:''
category:'Interface-Support-Controllers'
!
Controller comment:'
COPYRIGHT (c) 1992 by Claus Gittinger
All Rights Reserved
$Header: /cvs/stx/stx/libview/Controller.st,v 1.22 1995-07-02 16:15:18 claus Exp $
'!
!Controller class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 1992 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
version
"
$Header: /cvs/stx/stx/libview/Controller.st,v 1.22 1995-07-02 16:15:18 claus Exp $
"
!
documentation
"
Controllers can be used to controll the user-interactions
to a model which is shown in a view. For very simple views,
(and due to the evolution of Smalltalk/X) many view-classes have
the controller function integrated.
To allow both controller and non-controller operation, events are
sent directly to the view, if its controller instance variable
is nil. Otherwise, the controller gets the event.
For now (vsn 2.10.4) there are only a few view classes using controllers;
however, over time, more will be converted, since separating the controller
offers much more flexibility
(although view initialization becomes a bit more complex).
Instance variables:
view aView the view I controll
model aModel the model which is to be worked on
"
! !
!Controller class methodsFor:'instance creation'!
new
^ self basicNew initialize
! !
!Controller methodsFor:'initialize / release'!
initialize
"initialize the controller; subclasses should redefine
this and include a super initialize for proper initialization."
^ self
!
startUp
"startup the controller; this is sent when the view realizes,
right before it becomes visible.
Can be redefined in subclasses to do some startup action."
^ self
!
release
"close down the controller; this is sent when the view is destroyed.
Can be redefined in subclasses to do some cleanup action. However,
these redefined methods should do a super release."
view notNil ifTrue:[view controller:nil].
view := nil.
model := nil
! !
!Controller methodsFor:'ST-80 compatibility'!
open
"open my view"
view open
! !
!Controller methodsFor:'accessing'!
view:aView
"set my view"
view notNil ifTrue:[
model notNil ifTrue:[
model removeDependent:view
]
].
view := aView.
model notNil ifTrue:[
"/ model addDependent:view
view notNil ifTrue:[
view model:model
]
].
!
view
"return my view"
^ view
!
model:aModel
"set my model"
model notNil ifTrue:[
model removeDependent:view
].
model := aModel.
"/ model notNil ifTrue:[model addDependent:view]
!
model
"return my model"
^ model
!
sensor
"return my views sensor"
^ view sensor
!
menuHolder
"by default, the model has to provide the menu"
model isNil ifTrue:[^ view].
^ model
!
menuPerformer
"by default, the model is performing menu actions"
model isNil ifTrue:[^ view].
^ model
! !
!Controller methodsFor:'menus'!
yellowButtonMenu
"actually, this should be called 'middleButtonMenu'.
But for ST-80 compatibility ...."
|sym menuHolder m|
(m := view middleButtonMenu) notNil ifTrue:[
"/
"/ has been assigned a static middleButtonMenu
"/ (or a cached menu)
"/
^ m
].
menuHolder := self menuHolder.
"
try ST-80 style menus first:
if there is a model, and a menuMessage is defined,
ask model for the menu and launch that if non-nil.
"
(menuHolder notNil
and:[(sym := view menuMessage) notNil
and:[sym isSymbol]]) ifTrue:[
"
ask model for the menu
"
^ menuHolder perform:sym.
].
^ nil
! !
!Controller methodsFor:'event handling'!
redButtonActivity
"actually, this should be called 'leftButtonActivity'.
But for ST-80 compatibility ...."
^ self
!
yellowButtonActivity
"actually, this should be called 'middleButtonActivity'.
But for ST-80 compatibility ...."
|menu actionSelector menuPerformer|
menu := self yellowButtonMenu.
menu notNil ifTrue:[
menuPerformer := self menuPerformer.
"
got one, launch the menu. It is supposed
to return an actionSelector.
"
"
a temporary kludge: subMenus dont know about
actionSelectors yet ...
"
menu receiver isNil ifTrue:[
menu receiver:menuPerformer
] ifFalse:[
"
if the menu has an explicit receiver,
thats the one to do the work.
"
menuPerformer := menu receiver
].
actionSelector := menu startUp.
(actionSelector notNil
and:[actionSelector isSymbol]) ifTrue:[
menuPerformer perform:actionSelector
].
^ self
].
"
ST/X style static menus - going to be obsoleted ...
"
(menu := view middleButtonMenu) notNil ifTrue:[
menu showAtPointer
]
!
blueButtonActivity
"actually, this should be called 'rightButtonActivity'.
But for ST-80 compatibility ...."
^ self
! !
!Controller methodsFor:'low level events'!
buttonPress:button x:x y:y
"a mouse button was pressed in my view.
Translate buttonPress events into similar ST-80 type
event messages. This method and/or these ST-80 methods
can be redefined in subclasses"
((button == 1) or:[button == #select]) ifTrue:[
self redButtonActivity
].
((button == 2) or:[button == #menu]) ifTrue:[
self yellowButtonActivity
].
(button == 3) ifTrue:[
self blueButtonActivity
]
!
buttonMultiPress:button x:x y:y
"a mouse button was pressed again shortly after in my view"
^ self buttonPress:button x:x y:y
!
buttonShiftPress:button x:x y:y
"a mouse button was pressed again shortly after in my view"
^ self buttonPress:button x:x y:y
!
buttonRelease:button x:x y:y
"a mouse button was released in my view; nothing done here"
^ self
!
buttonMotion:buttonMask x:x y:y
"mouse was moved with button pressed in my view; nothing done here"
^ self
!
pointerEnter:state x:x y:y
"mouse pointer entered my view; nothing done here"
^ self
!
pointerLeave:state
"mouse pointer left my view; nothing done here"
^ self
!
focusIn
"my view got the keyboard focus; nothing done here"
^ self
!
focusOut
"my view lost keyboard focus; nothing done here"
^ self
!
keyPress:key x:x y:y
"key was pressed in my view; nothing done here"
^ self
!
keyRelease:key x:x y:y
"key was released in my view; nothing done here"
^ self
!
devicePointerEnter:state x:x y:y
"this is the low-level (untransformed) event as received
from the device (i.e. coordinates are in device coordinates).
If there is a transformation, apply the inverse
and send a pointerEnter with the logical coordinates."
|lx ly trans|
lx := x.
ly := y.
(trans := view transformation) notNil ifTrue:[
lx := trans applyInverseToX:lx.
ly := trans applyInverseToY:ly.
].
self pointerEnter:state x:lx y:ly
!
deviceKeyPress:key x:x y:y
"this is the low-level (untransformed) event as received
from the device (i.e. coordinates are in device coordinates).
If there is a transformation, apply the inverse
and send a keyPress with the logical coordinates."
|lx ly trans|
lx := x.
ly := y.
(trans := view transformation) notNil ifTrue:[
lx := trans applyInverseToX:lx.
ly := trans applyInverseToY:ly.
].
self keyPress:key x:lx y:ly
!
deviceKeyRelease:key x:x y:y
"this is the low-level (untransformed) event as received
from the device (i.e. coordinates are in device coordinates).
If there is a transformation, apply the inverse
and send a keyRelease with the logical coordinates."
|lx ly trans|
lx := x.
ly := y.
(trans := view transformation) notNil ifTrue:[
lx := trans applyInverseToX:lx.
ly := trans applyInverseToY:ly.
].
self keyRelease:key x:lx y:ly
!
deviceButtonPress:button x:x y:y
"this is the low-level (untransformed) event as received
from the device (i.e. coordinates are in device coordinates).
If there is a transformation, apply the inverse
and send a buttonPress with the logical coordinates."
|lx ly trans|
lx := x.
ly := y.
(trans := view transformation) notNil ifTrue:[
lx := trans applyInverseToX:lx.
ly := trans applyInverseToY:ly.
].
self buttonPress:button x:lx y:ly
!
deviceButtonRelease:button x:x y:y
"this is the low-level (untransformed) event as received
from the device (i.e. coordinates are in device coordinates).
If there is a transformation, apply the inverse
and send a buttonRelease with the logical coordinates."
|lx ly trans|
lx := x.
ly := y.
(trans := view transformation) notNil ifTrue:[
lx := trans applyInverseToX:lx.
ly := trans applyInverseToY:ly.
].
self buttonRelease:button x:lx y:ly
!
deviceButtonMotion:state x:x y:y
"this is the low-level (untransformed) event as received
from the device (i.e. coordinates are in device coordinates).
If there is a transformation, apply the inverse
and send a buttonMotion with the logical coordinates."
|lx ly trans|
lx := x.
ly := y.
(trans := view transformation) notNil ifTrue:[
lx := trans applyInverseToX:lx.
ly := trans applyInverseToY:ly.
].
self buttonMotion:state x:lx y:ly
! !