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