HandMorph mega mail
Stefan Matthias Aust
sma at 3plus4.de
Thu Mar 23 21:53:49 UTC 2000
The HandMorph is ugly. 230 methods. It's frightenend. It needs a redesign.
But as it's so large, I don't dare to do it alone. So because nobody
dared to touch this class, I have to send out this long email. It tries to
identify what the HandMorph's methods do and makes somes suggestions what
could be changed.
First of all, I'm one of these "separate model, view, and application
logic" guys. So I'm in favor for removing everything that looks like model
or application logic from that class.
Req. MFwk - as required by the Morphic framework
'initialization'
initForEvents
part-initialization after a World get control (bad name)
initialize
main initialization method (Req. MFwk)
'classification'
isHandMorph
some places wants do things differently for hands. A grabed morphs
does react to keyStrokes for example. Unfortunately, instead of this
method, often "isKindOf: HandMorph" is used.
'accessing'
argument
used by the menu commands to define a morph that is manipulated by
them (I think). The other accessor is called #setArgument: instead
of simply argument:
eventTransform
used by eventTransform: and stores a MorphicTransformation to
manipulate MorphicEvent's mouse coordinates for rotated, scaled or
translated (as done by the TransformationMorph) morphs.
eventTransform:
writing accessor, see above
lastEvent
the hand always stores the last event to be able to synthesize
mouse move events when the world polls #processEvents. I think this
should be a private property but some other morphs obviously can't
live without this breach of encapsulation
setArgument:
writing accessor, see above
targetOffset
the difference between the hand and some other grabed morph? Also
used during menu operation??
userInitials
each hand can have an attached string. The setter has been
categorized wrongly as 'geometry'
'cursor'
cursorBounds
the hand's cursor bounds - in contrast to its bounds which also
contains the userInitials bounding box.
showTemporaryCursor:
showTemporaryCursor:hotSpotOffset:
hands can show different cursors. I don't know why these cursors
are called temporary. Instead of always keeping a NormalCursor in
the associated variable, that variable is tested for nil and this
case is dealt special with??
'geometry'
changed
Req. MFw. The hand is special it doesn't forward damage to the world.
Instead, the hand records its own damage which is then added to the
world right before it is redrawing itself. Sounds just more difficult
to me.
As somebody probably noticed that a hardware cursor that has no
userInitials and doesn't carry other morphs doesn't do damage at all,
the world also asks #needsToBeDrawn.
Then, as yet another optimization, the hand saves the part of the
screen below it so that you can simply copy back that saved form
instead of redrawing that part of the world. However, this works
only if that region isn't part of a damaged world region...
fullBounds
Req. MFw. Add the hand's dropshadow, if carrying some morphs
invalidRect:
Do own damage recording. It's not called by the hand itself - as
this would happen by #changed which was overwritten - but as result
of carried morphs which need to change theirselves.
position
position:
Req. MFw. these contains an unwanted lazy initialisation
userInitials:
see above
'drawing'
colorForInsets
Req. MFw. for inset bevels, don't use the mouse color but the
world's color
drawOn:
Req. MFw. draw cursor - either normal or temporay - and userInitials
fullDrawOn:
Req. MFw. in contrast to normal morphs, draw first the submorphs and
then the hand. Also deal with the drop shadows.
This method looks really difficult and reimplements a good deal of
the drawing optimizations of the world. I don't really understand
why this all is needed.
hasChanged
has somebody called #changed on the hand?
needsToBeDrawn
Different position? Different set of submorphs? A new userInitials?
If something changed, we need to redraw the hand.
nonCachingFullDrawOn:
A variant of #fullDrawOn:
restoreSavedPatchOn:
savePatchFrom:
Optimization (see above) for removing the hand from the screen.
Before it is drawn, that part of the screen is saved and restored
later if the hand needs to be removed.
shadowForm
Looks very much like the same method of Morph!
shadowOffset
A constant that defined how much the drop shadow is moved to the
bottomright
trailMorph
Some player-logo-style stuff. Baeh!
updateCacheCanvasDepth:
Even more changing. The submorphs carried by the hand are also
drawn in a form so that when moving the hand, we don't need to always
redraw them but simply blit that form. This does only work if the
morphs aren't translucent and do no stepping.
'event handling'
addMouseOverMorph:
Arg. The PaintBox uses this method to manipulate the way, mouseEnter
and mouseLeave methods are generation. I don't like that.
checkForMoreKeyboard
polling the keyboard, Yeah.
gridPointRaw
the hand can be gridded. This POLLS for the current cursor point
applying the grid if needed
handleDragOver:
called from handleMouseMove: to do want a hand morph has to do -
that is obfuscating its real work, which is sending dragEnter,
dragLeave notifications to morphs who want to get them.
handleEvent:
called by processEvent (and a few other places) to dispatch
to other methods based on the event type.
handleMouseDown:
for example to this method, which generates mouseDown events.
handleMouseMove:
this sends out mouseMove events and also handles entering, leaving
and dragging.
handleMouseOver:
this handles entering and leaving
handleMouseUp:
and this mouseUp: events. If assures that a morph that gots a
mouseDown: will get also mouseUp: even if the mouse isn't positioned
over it anymore
keyboardFocus
support for a keyboard focus. This answers the morph that will
receive keyStroke: notifications
mouseOverList:
mouseOverList:rank:
for dragging and mouseover, it's important to know over which
morphs the hand is hovering; this deals only with toplevel morphs
as for example system windows
newKeyboardFocus:
set a new keyboard focus, send out keyboardFocusChanged:
notification. This method must be called by morphs which want to
register itself as a receiver for keyStroke: events.
newMouseFocus:
used by the MenuItemMorphs and some others for whatever? I don't know
exactly?? Probably something like to keep that morph active even if
the hand isn't positioned over that morph
noteSignificantEvent:
this is really strange?? Perhaps support for the event recorder?
No really...
pauseEventRecorderIn:
But this is for the event recorder
processEvents
And this is the main entry point which is called by the World
periodically to poll for events, send them out via handleEvent:
and make the whole framework work...
recipientForMouseDown:
privat, strange, something for menu support I guess
startReportingEventsTo:
stopReportingEventsTo:
these two methods are for the event recorder
transformEvent:
as described above, transform an event based on the hand's
transformation
updateMouseDownTransform
pardon?
'double click support'
checkForDoubleClick:
Not only normal mouse events are polled but also double click events
are generated by Squeak (in constrast to using host events which would
allow one to use the system settings). Now see
HandMorph>>doubleClickTime: if you want to change the default
resetClickState
reset the double click timer, it will be restarted with the next
click.
waitForClicksOrDrag:event:
pardon?
'grabbing/dropping'
attachMorph:
called a thousand times to add a morph to the hand which basically
means that the hand has grabed that morph. It's however different to
grabMorph: (see below) for reasons unknown to me
dropMorphsEvent:
carried morphs just have been droped. Do the notification to
interested morphs. The protocol used here is too difficult to
described for me with my current state of mind.
dropTargetFor:event:
helper for the above method
grabMorph:
make it beige. Does a lot of tests before it eventually implements
its own versin of #attachMorph:
grabMorphFromMenu:
and yet another attach/grab thing...
The following stuff doesn't belong to the HandMorph IMHO. The world morph
menu should be implemented by the WorldMorph (aka PasteUpMorph) itself and
most methods can be best moved to a nice singleton instance that represents
the global functions of the Smalltalk system. It might be also nice if
tools can be registered using that singleton instead of being hard coded
into the this morph.
Because I'm getting too tired, I'll here, hoping somebody else picks this up.
'world menu'
appearanceDo
appearanceMenu
buildWorldMenu
changesDo
changesMenu
debugDo
debugMenu
gridOnString
helpDo
helpMenu
loadProject
newMorph
openMenu
openWindow
openWorldInWindow
playfieldDo
playfieldMenu
remoteDo
remoteMenu
scriptingDo
scriptingMenu
standardFontDo
windowsDo
windowsMenu
worldMenuHelp
'world menu commands'
absorbUpdatesFromServer
argumentOrNil
assert
beIsolated
beThisWorldsModel
browseChangedMessages
browseMorphClass
browseMorphClassFor:
browsePlayerClass
buildDebugHandleMenuFor:
buildMorphHandleMenuFor:
buildMorphMenuFor:
callTempCommand
changeBackgroundColor
changeColor
changeColorForMorph:target:selector:originalColor:
changeColorTarget:forMorph:selector:originalColor:
changeColorTarget:selector:
changeColorTarget:selector:originalColor:
changeVariableType
chooseColor
chooseNewCostumeForArgument
chooseTargetSubmorphOf:caption:
classOfPasteBuffer
cleanUpWorld
clearPasteBuffer
closeUnchangedWindows
collapseAll
copyToPasteBuffer
defineTempCommand
deleteNonWindows
detachableScriptingSpace
dismissMorph
drawingClass
duplicateMorph
expandAll
exploreArgument
fileForRecentLog
findDirtyBrowsers
findDirtyWindows
findWindow
goBehind
grabDrawingFromScreen
grabMorph
inspectArgument
inspectArgumentInMorphic
inspectArgumentsPlayerInMorphic
inspectMorph
inspectMorphInMorphic
inspectPlayer
inspectWorldModel
invokeMenu:event:
invokeMetaMenu:
jumpToProject
lockMorph
maybeDuplicateMorph
nameMorph
newDrawingFromMenu
newMorphFromAlphabeticalList
newMorphOfClass:event:
objectToPaste
openBrowser
openChangeSorter:
openChangesLog
openConstructionProject
openEmail
openFileDirectly
openFileList
openIRC
openMVCProject
openMorphicProject
openPackageBrowser
openRecentChanges
openScrapsBook
openSelectorBrowser
openTranscript
openViewerForArgument
openWebBrowser
openWorkspace
operateOnSubmorph:event:
pasteMorph
placeArgumentIn
potentialEmbeddingTargets
printWorldOnFile
projectThumbnail
quitSession
readMorphFromAFile
resizeMorph
saveAndQuit
saveAs
saveAsPrototype
saveOnFile
savePictureOfWorld
saveSession
saveWorldInFile
selectEmbedTargetMorph:
selectSubmorphToOperateOn:sending:event:
setDisplayDepth
setGridSize
setGridding
showActions
startMessageTally
startThenBrowseMessageTally
subclassMorph
submorphNameFor:
unlockContents
unlockOneSubpart
writeInitMethodForModel
yellowButtonClickOnDesktopWithEvent:
'special gestures'
specialDrag:
specialGesture:
'halos'
addHalo:
chooseHaloSubmorphOf:caption:
invokeMetaMenuFor:
popUpHalo:
popUpHaloFromClick:
popUpHaloFromShiftClick:
popUpNewHaloFromClick:targets:
'remote morphic'
cleanupDeadConnections
connectRemoteUser
disconnectAllRemoteUsers
disconnectRemoteUser
readyToTransmit
reportLocalAddress
startTransmittingEventsTo:
stopTransmittingEventsTo:
transmitEvent:
'from EToyHand'
clearPaletteArea
endDisplaySuppression
formerOwner
formerPosition
makeNewDrawingInBounds:pasteUpMorph:
makeNewPlayerInstance
rejectDropMorph:event:
roundUpStrayObjects
showHiders
startDisplaySuppression
suppressDisplay
unlockWorldContents
'copying'
veryDeepCopyWith:
'file in/out'
objectForDataStream:
'private'
alphabeticalMorphMenu
releaseCachedState
splitNewMorphList:depth:
bye
--
Stefan Matthias Aust // Bevor wir fallen, fallen wir lieber auf.
More information about the Squeak-dev
mailing list
|