'From Squeak3.2alpha of 3 October 2001 [latest update: #4553] on 27 November 2001 at 3:54:34 pm'! "Change Set: haloMenu-sw Date: 27 November 2001 Author: Scott Wallace An attempt at rationalization of the now hopelessly-unwieldy red-halo menu for morphs. ¥ the clustering together of most (all?) of the standard checkbox-bearing items ¥ the factoring of groups of items into separate methods which return coherent submenus. ¥ menu items mirroring halo actions are provided generically; this allowed deletion of a number of custom methods that had served only to offer halo-action functionality. ¥ full access to all the new border styles is now available via menu. ¥ a new checkbox item governing whether an object should resist removal is added. When set, user confirmation is required before a dismiss-via-halo is carried out. ¥ a few minor rewordings tried out (those in love with 'sticky' might scream.) ¥ a slight regrouping of the world menu, and a fresh factoring of the world's halo menu. ¥ balloon-help provided for all top-level items in standard world menu. ¥ the old #addAddHand... protocol is left behind (though retained for backward compatibility with client code) -- it was *never* used for its announced purpose, and thus only added confusion. All morph-specific additions are now channeled through #addCustomMenuItems... ¥ if the new #selectiveHalos preference is true, then inappropriate halo handles are no longer offered in a halo. Thus, for example, if a morph is marked as being resistant to removal, it will not offer pink (dismiss) handle. NOTE: to regain the former comfort of the old regime, set the selectiveHalos preference back to false. This update sets it to true so you can immediately feel the difference." Preferences addPreference: #selectiveHalos categories: #( Halos) default: true balloonHelp: 'When this is set to true, halo handles that are deemed inappropriate are not shown. Thus, for example, if a morph is marked as resistant to removal, it will not offer a pink ''dismiss''.'. ! !BorderStyle class methodsFor: 'instance creation' stamp: 'sw 11/26/2001 16:05'! borderStyleChoices "Answer the superset of all supported borderStyle symbols" ^ #(simple inset raised complexAltFramed complexAltInset complexAltRaised complexFramed complexInset complexRaised)! ! !BorderStyle class methodsFor: 'instance creation' stamp: 'sw 11/26/2001 15:58'! borderStyleForSymbol: sym "Answer a border style corresponding to the given symbol" | aSymbol | aSymbol _ sym == #none ifTrue: [#simple] ifFalse: [sym]. ^ self perform: aSymbol! ! !BorderStyle class methodsFor: 'instance creation' stamp: 'sw 11/27/2001 15:22'! simple "Answer a simple border style" ^ SimpleBorder new! ! !HaloSpec methodsFor: 'printing' stamp: 'sw 11/15/2001 16:31'! printOn: aStream "Add a textual printout representing the receiver to a stream" super printOn: aStream. aStream nextPutAll: ' (', addHandleSelector asString, ' ', iconSymbol asString, ')'! ! !Morph methodsFor: 'accessing' stamp: 'sw 11/26/2001 16:18'! borderStyleForSymbol: aStyleSymbol "Answer a suitable BorderStyle for me of the type represented by a given symbol" | aStyle existing | aStyle _ BorderStyle borderStyleForSymbol: aStyleSymbol asSymbol. aStyle ifNil: [self error: 'bad style']. existing _ self borderStyle. aStyle width: existing width; baseColor: existing baseColor. ^ (self canDrawBorder: aStyle) ifTrue: [aStyle] ifFalse: [nil]! ! !Morph methodsFor: 'accessing' stamp: 'sw 11/2/2001 12:10'! couldHaveRoundedCorners "subclases unhappy with rounded corners reimplement" ^ false! ! !Morph methodsFor: 'accessing' stamp: 'sw 11/15/2001 16:33'! resistsRemoval "Answer whether the receiver is marked as resisting removal" ^ self hasProperty: #resistsRemoval! ! !Morph methodsFor: 'accessing' stamp: 'sw 11/15/2001 16:33'! resistsRemoval: aBoolean "Set the receiver's resistsRemoval property as indicated" aBoolean ifTrue: [self setProperty: #resistsRemoval toValue: true] ifFalse: [self removeProperty: #resistsRemoval]! ! !Morph methodsFor: 'accessing' stamp: 'sw 11/26/2001 16:16'! setBorderStyle: aSymbol "Set the border style of my costume" | aStyle | aStyle _ self borderStyleForSymbol: aSymbol. aStyle ifNil: [^ self]. (self canDrawBorder: aStyle) ifTrue: [self borderStyle: aStyle]! ! !Morph methodsFor: 'accessing' stamp: 'sw 11/15/2001 12:21'! toggleResistsRemoval "Toggle the resistsRemoval property" self resistsRemoval ifTrue: [self removeProperty: #resistsRemoval] ifFalse: [self setProperty: #resistsRemoval toValue: true]! ! !Morph methodsFor: 'copying' stamp: 'sw 11/27/2001 11:59'! usableSiblingInstance "Return another similar morph whose Player is of the same class as mine" | aName usedNames newPlayer newMorph topRenderer | (topRenderer _ self topRendererOrSelf) == self ifFalse: [^ topRenderer usableSiblingInstance]. self assuredPlayer assureUniClass. newMorph _ self veryDeepCopyWithSiblingOf: self player. newPlayer _ newMorph player. newPlayer resetCostumeList. (aName _ self knownName) == nil ifTrue: [self player ~~ nil ifTrue: [aName _ newMorph innocuousName]]. "Force a difference here" aName ~~ nil ifTrue: [usedNames _ (self world ifNil: [OrderedCollection new] ifNotNil: [ self world allKnownNames]) copyWith: aName. newMorph setNameTo: (Utilities keyLike: aName satisfying: [:f | (usedNames includes: f) not])]. newMorph privateOwner: nil. (newMorph renderedMorph eventHandler ~~ nil) ifTrue: [newPlayer assureEventHandlerRepresentsStatus]. self currentWorld addMorphBack: newMorph. self presenter flushPlayerListCache. ^ newMorph! ! !Morph methodsFor: 'submorphs-add/remove' stamp: 'sw 11/27/2001 11:45'! dismissViaHalo "The user has clicked in the delete halo-handle. This provides a hook in case some concomitant action should be taken, or if the particular morph is not one which should be put in the trash can, for example." self resistsRemoval ifTrue: [(PopUpMenu confirm: 'Really throw this away' trueChoice: 'Yes' falseChoice: 'Um, no, let me reconsider') ifFalse: [^ self]]. Preferences preserveTrash ifFalse: [^ self dismissMorph]. TrashCanMorph moveToTrash: self! ! !Morph methodsFor: 'drawing' stamp: 'sw 11/27/2001 11:30'! hasClipSubmorphsString "Answer a string that represents the clip-submophs checkbox" ^ self clipSubmorphs ifTrue:['provide clipping'] ifFalse:['provide clipping']! ! !Morph methodsFor: 'menus' stamp: 'sw 11/27/2001 15:28'! adMiscExtrasTo: aMenu "Add a submenu of miscellaneous extra items to the menu." | realOwner realMorph subMenu | subMenu _ MenuMorph new defaultTarget: self. (self isWorldMorph not and: [(self renderedMorph isKindOf: SystemWindow) not]) ifFalse: [subMenu add: 'put in a window' action: #embedInWindow]. self isWorldMorph ifFalse: [subMenu add: 'adhere to edge...' action: #adhereToEdge. subMenu addLine]. realOwner _ (realMorph _ self topRendererOrSelf) owner. (realOwner isKindOf: TextPlusPasteUpMorph) ifTrue: [subMenu add: 'GeeMail stuff...' subMenu: (realOwner textPlusMenuFor: realMorph)]. self affiliatedSelector ifNotNil: [subMenu add: 'open a messenger' action: #openMessenger. subMenu balloonTextForLastItem: 'Open a Messenger on the actual method call used when the button action of this object is triggered.'. subMenu addLine]. subMenu add: 'add mouse up action' action: #addMouseUpAction; add: 'remove mouse up action' action: #removeMouseUpAction; add: 'hand me tiles to fire this button' action: #handMeTilesToFire. subMenu addLine. subMenu defaultTarget: self topRendererOrSelf. subMenu add: 'draw new path' action: #definePath. subMenu add: 'follow existing path' action: #followPath. subMenu add: 'delete existing path' action: #deletePath. subMenu addLine. self addGenieMenuItems: subMenu hand: ActiveHand. aMenu add: 'extras...' subMenu: subMenu ! ! !Morph methodsFor: 'menus' stamp: 'sw 11/27/2001 14:36'! addAddHandMenuItemsForHalo: aMenu hand: aHandMorph "The former charter of this method was to add halo menu items that pertained specifically to the hand. Over time this charter has withered, and most morphs reimplement this method simply to add their morph-specific menu items. So in the latest round, all other implementors in the standard image have been removed. However, this is left here as a hook for the benefit of existing code in client uses." ! ! !Morph methodsFor: 'menus' stamp: 'sw 11/27/2001 11:25'! addCopyItemsTo: aMenu "Add copy-like items to the halo menu" | subMenu | subMenu _ MenuMorph new defaultTarget: self. subMenu add: 'copy to paste buffer' action: #copyToPasteBuffer:. subMenu add: 'copy Postscript' action: #clipPostscript. subMenu add: 'print Postscript to file...' target: self selector: #printPSToFile. aMenu add: 'copy & print...' subMenu: subMenu! ! !Morph methodsFor: 'menus' stamp: 'sw 11/27/2001 07:17'! addCustomMenuItems: aCustomMenu hand: aHandMorph "Add morph-specific items to the given menu which was invoked by the given hand. This method provides is invoked both from the halo-menu and from the control-menu regimes." ! ! !Morph methodsFor: 'menus' stamp: 'sw 11/27/2001 15:26'! addHaloActionsTo: aMenu "Add items to aMenu representing actions requestable via halo" | subMenu | subMenu _ MenuMorph new defaultTarget: self. subMenu addTitle: self externalName. subMenu addStayUpItemSpecial. subMenu addLine. subMenu add: 'delete' action: #dismissViaHalo. subMenu balloonTextForLastItem: 'Delete this object -- warning -- can be destructive!!'. self maybeAddCollapseItemTo: subMenu. subMenu add: 'grab' action: #openInHand. subMenu balloonTextForLastItem: 'Pick this object up -- warning, since this removes it from its container, it can have adverse effects.'. subMenu addLine. subMenu add: 'resize' action: #resizeFromMenu. subMenu balloonTextForLastItem: 'Change the size of this object'. subMenu add: 'duplicate' action: #maybeDuplicateMorph. subMenu balloonTextForLastItem: 'Hand me a copy of this object'. subMenu addLine. subMenu add: 'property sheet' target: self renderedMorph action: #openAPropertySheet. subMenu balloonTextForLastItem: 'Open a property sheet for me. Allows changing lots of stuff at once.'. subMenu add: 'set color' target: self renderedMorph action: #changeColor. subMenu balloonTextForLastItem: 'Change the color of this object'. subMenu add: 'viewer' target: self action: #beViewed. subMenu balloonTextForLastItem: 'Open a Viewer that will allow everything about this object to be seen and controlled.'. subMenu add: 'tile browser' target: self action: #openInstanceBrowserWithTiles. subMenu balloonTextForLastItem: 'Open a tool that will facilitate tile scripting of this object.'. subMenu add: 'hand me a tile' target: self action: #tearOffTile. subMenu balloonTextForLastItem: 'Hand me a tile represting this object'. subMenu addLine. subMenu add: 'inspect' target: self action: #inspect. subMenu balloonTextForLastItem: 'Open an Inspector on this object'. aMenu add: 'halo actions...' subMenu: subMenu ! ! !Morph methodsFor: 'menus' stamp: 'sw 11/27/2001 12:02'! addPlayerItemsTo: aMenu "Add player-related items to the menu if appropriate" | aPlayer subMenu | aPlayer _ self topRendererOrSelf player. subMenu _ MenuMorph new defaultTarget: self. subMenu add: 'make a sibling instance' target: self action: #makeNewPlayerInstance:. subMenu balloonTextForLastItem: 'Makes another morph whose player is of the same class as this one. Both siblings will share the same scripts'. subMenu add: 'make multiple siblings...' target: self action: #makeMultipleSiblings:. subMenu balloonTextForLastItem: 'Make any number of sibling instances all at once'. (aPlayer belongsToUniClass and: [aPlayer class instanceCount > 1]) ifTrue: [subMenu addLine. subMenu add: 'make all siblings look like me' target: self action: #makeSiblingsLookLikeMe:. subMenu balloonTextForLastItem: 'make all my sibling instances look like me.'. subMenu add: 'bring all siblings to my location' target: self action: #bringAllSiblingsToMe:. subMenu balloonTextForLastItem: 'find all sibling instances and bring them to me'. subMenu add: 'apply status to all siblngs' target: self action: #applyStatusToAllSiblings:. subMenu balloonTextForLastItem: 'apply the current status of all of my scripts to the scripts of all my siblings']. aMenu add: 'siblings...' subMenu: subMenu ! ! !Morph methodsFor: 'menus' stamp: 'sw 11/26/2001 19:09'! addStackItemsTo: aMenu "Add stack-related items to the menu" | stackSubMenu | stackSubMenu _ MenuMorph new defaultTarget: self. (owner notNil and: [owner isStackBackground]) ifTrue: [self isShared ifFalse: [stackSubMenu add: 'put onto Background' target: self action: #putOnBackground] ifTrue: [stackSubMenu add: 'remove from Background' target: self action: #putOnForeground. self couldHoldSeparateDataForEachInstance ifTrue: [self holdsSeparateDataForEachInstance ifFalse: [stackSubMenu add: 'start holding separate data for each instance' target: self action: #makeHoldSeparateDataForEachInstance] ifTrue: [stackSubMenu add: 'stop holding separate data for each instance' target: self action: #stopHoldingSeparateDataForEachInstance]. stackSubMenu add: 'be default value on new card' target: self action: #setAsDefaultValueForNewCard. (self hasProperty: #thumbnailImage) ifTrue: [stackSubMenu add: 'stop using for reference thumbnail' target: self action: #stopUsingForReferenceThumbnail] ifFalse: [stackSubMenu add: 'start using for reference thumbnail' target: self action: #startUsingForReferenceThumbnail]]]. stackSubMenu addLine]. (self isStackBackground) ifFalse: [stackSubMenu add: 'be a card in an existing stack...' action: #insertAsStackBackground]. stackSubMenu add: 'make an instance for my data' action: #abstractAModel. (self isStackBackground) ifFalse: [stackSubMenu add: 'become a stack of cards' action: #wrapWithAStack]. aMenu add: 'stacks and cards...' subMenu: stackSubMenu ! ! !Morph methodsFor: 'menus' stamp: 'sw 11/27/2001 09:24'! addStandardHaloMenuItemsTo: aMenu hand: aHandMorph "Add standard halo items to the menu" | unlockables | self isWorldMorph ifTrue: [^ self addWorldHaloMenuItemsTo: aMenu hand: aHandMorph]. self mustBeBackmost ifFalse: [aMenu add: 'send to back' action: #goBehind. aMenu add: 'bring to front' action: #comeToFront. self potentialEmbeddingTargets size > 1 ifTrue: [aMenu add: 'embed...' target: self action: #embedInto:]. aMenu addLine]. self addFillStyleMenuItems: aMenu hand: aHandMorph. self addBorderStyleMenuItems: aMenu hand: aHandMorph. self addDropShadowMenuItems: aMenu hand: aHandMorph. self addLayoutMenuItems: aMenu hand: aHandMorph. self addHaloActionsTo: aMenu. aMenu addLine. self addToggleItemsToHaloMenu: aMenu. aMenu addLine. self addCopyItemsTo: aMenu. self addPlayerItemsTo: aMenu. self addExportMenuItems: aMenu hand: aHandMorph. self addStackItemsTo: aMenu. self adMiscExtrasTo: aMenu. Preferences noviceMode ifFalse: [self addDebuggingItemsTo: aMenu hand: aHandMorph]. aMenu addLine. aMenu defaultTarget: self. aMenu addLine. unlockables _ self submorphs select: [:m | m isLocked]. unlockables size == 1 ifTrue: [aMenu add: 'unlock "', unlockables first externalName, '"' action: #unlockContents]. unlockables size > 1 ifTrue: [aMenu add: 'unlock all contents' action: #unlockContents. aMenu add: 'unlock...' action: #unlockOneSubpart]. aMenu defaultTarget: aHandMorph. ! ! !Morph methodsFor: 'menus' stamp: 'sw 11/27/2001 15:00'! addToggleItemsToHaloMenu: aMenu "Add standard true/false-checkbox items to the memu" #((resistsRemovalString toggleResistsRemoval 'whether I should be reistant to easy removal from my container via the pink X handle') (stickinessString toggleStickiness 'whether I should be resistant to a drag done by mousing down on me') (lockedString lockUnlockMorph 'when "locked", I am inert to all user interactions') (hasClipSubmorphsString changeClipSubmorphs 'whether the parts of objects within me that are outside my bounds should be masked.') (hasDragAndDropEnabledString changeDragAndDrop 'whether I am open to have objects dropped into me')) do: [:trip | aMenu addUpdating: trip first action: trip second. aMenu balloonTextForLastItem: trip third]. self couldHaveRoundedCorners ifTrue: [aMenu addUpdating: #roundedCornersString action: #toggleCornerRounding. aMenu balloonTextForLastItem: 'whether my corners should be rounded']! ! !Morph methodsFor: 'menus' stamp: 'sw 11/27/2001 15:00'! hasDragAndDropEnabledString "Answer a string to characterize the drag & drop status of the receiver" ^ self dragNDropEnabled ifTrue:['accept drops'] ifFalse:['accept drops']! ! !Morph methodsFor: 'menus' stamp: 'sw 11/27/2001 11:29'! lockedString "Answer the string to be shown in a menu to represent the 'locked' status" ^ self isLocked ifTrue: ['be locked'] ifFalse: ['be locked']! ! !Morph methodsFor: 'menus' stamp: 'sw 11/21/2001 12:09'! resistsRemovalString "Answer the string to be shown in a menu to represent the 'resistsRemoval' status" ^ self resistsRemoval ifTrue: ['resist removal'] ifFalse: ['resist removal']! ! !Morph methodsFor: 'menus' stamp: 'sw 11/27/2001 11:24'! stickinessString "Answer the string to be shown in a menu to represent the stickiness status" ^ self isSticky ifTrue: ['resist drag'] ifFalse: ['resist drag'] ! ! !Morph methodsFor: 'halos and balloon help' stamp: 'sw 11/15/2001 16:31'! addHandlesTo: aHaloMorph box: box "Add halo handles to the halo. Apply the halo filter if appropriate" | wantIt | aHaloMorph haloBox: box. Preferences haloSpecifications do: [:aSpec | wantIt _ Preferences selectiveHalos ifTrue: [self wantsHaloHandleWithSelector: aSpec addHandleSelector inHalo: aHaloMorph] ifFalse: [true]. wantIt ifTrue: [aHaloMorph perform: aSpec addHandleSelector with: aSpec]]. aHaloMorph innerTarget addOptionalHandlesTo: aHaloMorph box: box! ! !Morph methodsFor: 'halos and balloon help' stamp: 'sw 11/15/2001 12:23'! okayToAddDismissHandle "Answer whether a halo on the receiver should offer a dismiss handle. This provides a hook for making it harder to disassemble some strucures even momentarily" ^ self holdsSeparateDataForEachInstance not and: [self resistsRemoval not]! ! !Morph methodsFor: 'halos and balloon help' stamp: 'sw 11/27/2001 14:50'! okayToBrownDragEasily "Answer whether it it okay for the receiver to be brown-dragged easily -- i.e. repositioned within its container without extracting it. At present this is just a hook -- nobody declines." ^ true " ^ (self topRendererOrSelf owner isKindOf: PasteUpMorph) and: [self layoutPolicy isNil]"! ! !Morph methodsFor: 'halos and balloon help' stamp: 'sw 11/27/2001 15:02'! okayToExtractEasily "Answer whether it it okay for the receiver to be extracted easily. Not yet hooked up to the halo-permissions mechanism." ^ self topRendererOrSelf owner dragNDropEnabled! ! !Morph methodsFor: 'halos and balloon help' stamp: 'sw 11/15/2001 16:32'! okayToResizeEasily "Answer whether it is appropriate to have the receiver be easily resized by the user from the halo" ^ (self topRendererOrSelf owner isKindOf: PasteUpMorph) and: [self layoutPolicy isNil]! ! !Morph methodsFor: 'halos and balloon help' stamp: 'sw 11/27/2001 14:44'! okayToRotateEasily "Answer whether it is appropriate for a rotation handle to be shown for the receiver. This is a hook -- at present nobody declines." ^ true! ! !Morph methodsFor: 'halos and balloon help' stamp: 'sw 11/27/2001 14:49'! wantsHaloHandleWithSelector: aSelector inHalo: aHaloMorph "Answer whether the receiver would like to offer the halo handle with the given selector (e.g. #addCollapseHandle:)" (#(addDismissHandle:) includes: aSelector) ifTrue: [^ self resistsRemoval not]. (#( addDragHandle: ) includes: aSelector) ifTrue: [^ self okayToBrownDragEasily]. (#(addGrowHandle: addScaleHandle:) includes: aSelector) ifTrue: [^ self okayToResizeEasily]. (#( addRotateHandle: ) includes: aSelector) ifTrue: [^ self okayToRotateEasily]. (#(addRecolorHandle:) includes: aSelector) ifTrue: [^ self renderedMorph wantsRecolorHandle]. true ifTrue: [^ true] ! ! !Morph methodsFor: 'e-toy support' stamp: 'sw 11/27/2001 14:52'! wantsRecolorHandle "Answer whether the receiver would like a recoloring halo handle to be put up. Since this handle also presently affords access to the property-sheet, it is presently always allowed, even though SketchMorphs don't like regular recoloring" ^ true ! ! !Morph methodsFor: 'rounding' stamp: 'sw 11/27/2001 11:31'! roundedCornersString "Answer the string to put in a menu that will invite the user to switch to the opposite corner-rounding mode" ^ (self wantsRoundedCorners ifTrue: [''] ifFalse: ['']), 'round corners' ! ! !Morph methodsFor: 'meta-actions' stamp: 'sw 11/27/2001 10:50'! buildHandleMenu: aHand "Build the morph menu for the given morph's halo's menu handle. This menu has two sections. The first section contains commands that are interpreted by the hand; the second contains commands provided by the target morph. This method allows the morph to decide which items should be included in the hand's section of the menu." | menu | menu _ MenuMorph new defaultTarget: self. menu addStayUpItem. menu addLine. self addStandardHaloMenuItemsTo: menu hand: aHand. menu defaultTarget: aHand. self addAddHandMenuItemsForHalo: menu hand: aHand. menu defaultTarget: self. self addCustomHaloMenuItems: menu hand: aHand. menu defaultTarget: aHand. ^ menu ! ! !Morph methodsFor: 'meta-actions' stamp: 'sw 11/27/2001 07:07'! buildMetaMenu: evt "Build the morph menu. This menu has two sections. The first section contains commands that are handled by the hand; the second contains commands handled by the argument morph." | menu | menu _ MenuMorph new defaultTarget: self. menu addStayUpItem. menu add: 'grab' action: #grabMorph:. menu add: 'copy to paste buffer' action: #copyToPasteBuffer:. self maybeAddCollapseItemTo: menu. menu add: 'delete' action: #dismissMorph:. menu addLine. menu add: 'copy Postscript' action: #clipPostscript. menu add: 'print PS to file...' action: #printPSToFile. menu addLine. menu add: 'go behind' action: #goBehind. menu add: 'add halo' action: #addHalo:. menu add: 'duplicate' action: #maybeDuplicateMorph:. self potentialEmbeddingTargets size > 1 ifTrue: [menu add: 'embed...' action: #embedInto:]. menu add: 'resize' action: #resizeMorph:. "Give the argument control over what should be done about fill styles" self addFillStyleMenuItems: menu hand: evt hand. self addDropShadowMenuItems: menu hand: evt hand. self addLayoutMenuItems: menu hand: evt hand. menu addUpdating: #hasClipSubmorphsString target: self selector: #changeClipSubmorphs argumentList: #(). menu addLine. (self morphsAt: evt position) size > 1 ifTrue: [menu add: 'submorphs...' target: self selector: #invokeMetaMenuAt:event: argument: evt position]. menu addLine. menu add: 'inspect' selector: #inspectAt:event: argument: evt position. menu add: 'explore' action: #explore. menu add: 'browse hierarchy' action: #browseHierarchy. menu add: 'make own subclass' action: #subclassMorph. menu addLine. menu add: 'set variable name...' action: #choosePartName. (self isMorphicModel) ifTrue: [menu add: 'save morph as prototype' action: #saveAsPrototype. (self ~~ self world modelOrNil) ifTrue: [menu add: 'become this world''s model' action: #beThisWorldsModel]]. menu add: 'save morph in file' action: #saveOnFile. (self hasProperty: #resourceFilePath) ifTrue: [((self valueOfProperty: #resourceFilePath) endsWith: '.morph') ifTrue: [menu add: 'save as resource' action: #saveAsResource]. menu add: 'update from resource' action: #updateFromResource] ifFalse: [menu add: 'attach to resource' action: #attachToResource]. menu add: 'show actions' action: #showActions. menu addLine. self addDebuggingItemsTo: menu hand: evt hand. self addCustomMenuItems: menu hand: evt hand. ^ menu ! ! !Morph methodsFor: 'meta-actions' stamp: 'sw 11/27/2001 14:59'! dismissMorph "Dismiss the morph" ^ self dismissMorph: ActiveEvent! ! !Morph methodsFor: 'meta-actions' stamp: 'sw 11/27/2001 08:12'! maybeDuplicateMorph "Maybe duplicate the morph" self okayToDuplicate ifTrue: [self duplicate openInHand]! ! !Morph methodsFor: 'meta-actions' stamp: 'sw 11/27/2001 14:59'! resizeFromMenu "Commence an interaction that will resize the receiver" self resizeMorph: ActiveEvent! ! !Morph methodsFor: 'messenger' stamp: 'sw 11/3/2001 12:23'! affiliatedSelector "Answer a selector affiliated with the receiver for the purposes of launching a messenger. Reimplement this to plug into the messenger service" ^ nil! ! !Morph methodsFor: 'menu' stamp: 'sw 11/27/2001 15:21'! addBorderStyleMenuItems: aMenu hand: aHandMorph "Probably one could offer border-style items even if it's not a borderedMorph, so this remains a loose end for the moment" ! ! !BorderedMorph methodsFor: 'menu' stamp: 'sw 11/27/2001 15:20'! addBorderStyleMenuItems: aMenu hand: aHandMorph "Add border-style menu items" | subMenu | subMenu _ MenuMorph new defaultTarget: self. subMenu addTitle: 'border'. subMenu addStayUpItemSpecial. subMenu addList: #(('border color...' changeBorderColor:) ('border width...' changeBorderWidth:)). subMenu addLine. BorderStyle borderStyleChoices do: [:sym | (self borderStyleForSymbol: sym) ifNotNil: [subMenu add: sym target: self selector: #setBorderStyle: argument: sym]]. aMenu add: 'border style...' subMenu: subMenu ! ! !FlapTab methodsFor: 'menu' stamp: 'sw 11/27/2001 10:52'! addCustomMenuItems: aMenu hand: aHandMorph "Add further items to the menu as appropriate" aMenu add: 'tab color...' target: self action: #changeColor. aMenu add: 'flap color...' target: self action: #changeFlapColor. aMenu addLine. aMenu addUpdating: #edgeString action: #setEdgeToAdhereTo. aMenu addLine. aMenu addUpdating: #textualTabString action: #textualTab. aMenu addUpdating: #graphicalTabString action: #graphicalTab. aMenu addUpdating: #solidTabString enablement: #notSolid action: #solidTab. aMenu addLine. (referent isKindOf: PasteUpMorph) ifTrue: [aMenu addUpdating: #partsBinString action: #togglePartsBinMode]. aMenu addUpdating: #dragoverString action: #toggleDragOverBehavior. aMenu addUpdating: #mouseoverString action: #toggleMouseOverBehavior. aMenu addLine. aMenu addUpdating: #isGlobalFlapString enablement: #sharedFlapsAllowed action: #toggleIsGlobalFlap. aMenu balloonTextForLastItem: 'If checked, this flap will be available in all morphic projects; if not, it will be private to this project.,'. aMenu addLine. aMenu add: 'destroy this flap' action: #destroyFlap. "aMenu addUpdating: #slideString action: #toggleSlideBehavior. aMenu addUpdating: #inboardString action: #toggleInboardness. aMenu addUpdating: #thicknessString ('thickness... (current: ', self thickness printString, ')') action: #setThickness." ! ! !FlapTab methodsFor: 'menu' stamp: 'sw 11/27/2001 12:13'! dismissViaHalo "Dismiss the receiver (and its referent), unless it resists" self resistsRemoval ifTrue: [(PopUpMenu confirm: 'Really throw this flap away' trueChoice: 'Yes' falseChoice: 'Um, no, let me reconsider') ifFalse: [^ self]]. referent delete. self delete! ! !FunctionComponent methodsFor: 'menu' stamp: 'sw 11/27/2001 14:57'! addCustomMenuItems: aMenu hand: aHandMorph "Add custom menu items" super addCustomMenuItems: aMenu hand: aHandMorph. aMenu add: 'add pin' target: self selector: #addPin. ! ! !HaloMorph methodsFor: 'handles' stamp: 'sw 11/27/2001 11:18'! addDismissHandle: handleSpec "Add the dismiss handle according to the spec, unless selectiveHalos is on and my target resists dismissal" | dismissHandle | (target okayToAddDismissHandle or: [Preferences selectiveHalos not]) ifTrue: [dismissHandle _ self addHandle: handleSpec on: #mouseDown send: #mouseDownInDimissHandle:with: to: self. dismissHandle on: #mouseUp send: #maybeDismiss:with: to: self. dismissHandle on: #mouseDown send: #setDismissColor:with: to: self. dismissHandle on: #mouseMove send: #setDismissColor:with: to: self] ! ! !ObjectsTool methodsFor: 'menu' stamp: 'sw 11/27/2001 11:42'! addCustomMenuItems: aMenu hand: aHand "Add items to the given halo-menu, given a hand" super addCustomMenuItems: aMenu hand: aHand. aMenu addLine. aMenu add: 'alphabetic' target: self selector: #showAlphabeticTabs. aMenu add: 'find' target: self selector: #showSearchPane. aMenu add: 'categories' target: self selector: #showCategories. aMenu addLine. aMenu add: 'reset thumbnails' target: self selector: #resetThumbnails.! ! !PasteUpMorph methodsFor: 'menu & halo' stamp: 'sw 11/27/2001 06:56'! addCustomMenuItems: menu hand: aHandMorph "Add morph-specific menu itemns to the menu for the hand" super addCustomMenuItems: menu hand: aHandMorph. self addStackMenuItems: menu hand: aHandMorph. self addPenMenuItems: menu hand: aHandMorph. self addPlayfieldMenuItems: menu hand: aHandMorph. self isWorldMorph ifTrue: [(owner isKindOf: BOBTransformationMorph) ifTrue: [self addScalingMenuItems: menu hand: aHandMorph]. Flaps sharedFlapsAllowed ifTrue: [menu addUpdating: #suppressFlapsString target: CurrentProjectRefactoring action: #currentToggleFlapsSuppressed]. menu add: 'desktop menu...' target: self action: #putUpDesktopMenu:]. menu addLine! ! !PasteUpMorph methodsFor: 'menu & halo' stamp: 'sw 11/27/2001 14:37'! addWorldHaloMenuItemsTo: aMenu hand: aHandMorph "Add standard halo items to the menu, given that the receiver is a World" | unlockables | self addFillStyleMenuItems: aMenu hand: aHandMorph. self addLayoutMenuItems: aMenu hand: aHandMorph. aMenu addLine. self addWorldToggleItemsToHaloMenu: aMenu. aMenu addLine. self addCopyItemsTo: aMenu. self addPlayerItemsTo: aMenu. self addExportMenuItems: aMenu hand: aHandMorph. self addStackItemsTo: aMenu. self adMiscExtrasTo: aMenu. Preferences noviceMode ifFalse: [self addDebuggingItemsTo: aMenu hand: aHandMorph]. aMenu addLine. aMenu defaultTarget: self. aMenu addLine. unlockables _ self submorphs select: [:m | m isLocked]. unlockables size == 1 ifTrue: [aMenu add: 'unlock "', unlockables first externalName, '"' action: #unlockContents]. unlockables size > 1 ifTrue: [aMenu add: 'unlock all contents' action: #unlockContents. aMenu add: 'unlock...' action: #unlockOneSubpart]. aMenu defaultTarget: aHandMorph. ! ! !PasteUpMorph methodsFor: 'menu & halo' stamp: 'sw 11/27/2001 15:00'! addWorldToggleItemsToHaloMenu: aMenu "Add toggle items for the world to the halo menu" #( (hasDragAndDropEnabledString changeDragAndDrop 'whether I am open to have objects dropped into me') (roundedCornersString toggleCornerRounding 'whether the world should have rounded corners')) do: [:trip | aMenu addUpdating: trip first action: trip second. aMenu balloonTextForLastItem: trip third]! ! !PhraseTileMorph methodsFor: 'miscellaneous' stamp: 'sw 11/27/2001 12:24'! addCustomMenuItems: aMenu hand: aHand "Add additional items to the halo manu" super addCustomMenuItems: aMenu hand: aHand. aMenu add: 'Sprout a new scriptor around this phrase' target: self action: #sproutNewScriptor! ! !Player methodsFor: 'slot getters/setters' stamp: 'sw 11/15/2001 16:34'! getResistsRemoval "Answer whether the receiver is marked to resist removal" ^ costume resistsRemoval! ! !Player methodsFor: 'slot getters/setters' stamp: 'sw 11/26/2001 16:20'! setBorderStyle: aSymbol "Set the border style of my costume" costume renderedMorph setBorderStyle: aSymbol! ! !Player methodsFor: 'slot getters/setters' stamp: 'sw 11/15/2001 16:34'! setResistsRemoval: aBoolean "Set the resistsRemoval property" ^ costume resistsRemoval: aBoolean! ! !PluggableListMorph methodsFor: 'menus' stamp: 'sw 11/27/2001 14:32'! addCustomMenuItems: aMenu hand: aHandMorph "Add halo menu items to be handled by the invoking hand. The halo menu is invoked by clicking on the menu-handle of the receiver's halo." super addCustomMenuItems: aMenu hand: aHandMorph. aMenu addLine. aMenu add: 'list font...' target: self action: #setListFont. aMenu addLine ! ! !ScriptEditorMorph methodsFor: 'dropping/grabbing' stamp: 'sw 11/15/2001 12:30'! dismissViaHalo "The user has clicked in the delete halo-handle. This provides a hook in case some concomitant action should be taken, or if the particular morph is not one which should be put in the trash can, for example." self resistsRemoval ifTrue: [^ self]. self destroyScript! ! !SelectionMorph methodsFor: 'halo commands' stamp: 'sw 11/27/2001 14:30'! addCustomMenuItems: aMenu hand: aHandMorph "Add custom menu items to the menu" super addCustomMenuItems: aMenu hand: aHandMorph. aMenu addLine. aMenu add: 'add or remove items' target: self selector: #addOrRemoveItems: argument: aHandMorph. aMenu addLine. aMenu add: 'place into a row' target: self selector: #organizeIntoRow. aMenu add: 'place into a column' target: self selector: #organizeIntoColumn. aMenu addLine. ! ! !SketchMorph methodsFor: 'initialization' stamp: 'sw 11/27/2001 15:25'! couldHaveRoundedCorners "Answer whether the receiver could have rounded corners" ^ true! ! !SketchMorph methodsFor: 'menu' stamp: 'sw 11/27/2001 15:23'! addCustomMenuItems: aCustomMenu hand: aHandMorph "Add custom menu items" super addCustomMenuItems: aCustomMenu hand: aHandMorph. aCustomMenu add: 'choose new graphic...' target: self action: #chooseNewGraphic. aCustomMenu add: 'set as background' target: rotatedForm action: #setAsBackground. self addPaintingItemsTo: aCustomMenu hand: aHandMorph! ! !SketchMorph methodsFor: 'menu' stamp: 'sw 11/27/2001 15:25'! addToggleItemsToHaloMenu: aCustomMenu "Add toggle-items to the halo menu" super addToggleItemsToHaloMenu: aCustomMenu. aCustomMenu addUpdating: #useInterpolationString target: self action: #toggleInterpolation.! ! !SketchMorph methodsFor: 'e-toy support' stamp: 'sw 11/27/2001 14:52'! wantsRecolorHandle "Answer whether the receiver would like a recolor handle to be put up for it. We'd want to disable this but for the moment that would cut off access to the button part of the properties sheet. So this remains a loose end." ^ super wantsRecolorHandle ! ! !TheWorldMenu methodsFor: 'construction' stamp: 'sw 11/27/2001 15:19'! buildWorldMenu "Build the menu that is put up when the screen-desktop is clicked on" | menu | menu _ MenuMorph new defaultTarget: self. self colorForDebugging: menu. menu addStayUpItem. self fillIn: menu from: { {'previous project' . { #myWorld . #goBack }. 'return to the most-recently-visited project'}. {'jump to project...' . { #myWorld . #jumpToProject }. 'put up a list of all projects, letting me choose one to go to' }. {'save project on file...' . { #myWorld . #saveOnFile }. 'save this project on a file' }. {'load project from file...' . { self . #loadProject }. 'load a project from a file' }. nil}. myWorld addUndoItemsTo: menu. self fillIn: menu from: { {'restore display (r)' . { World . #restoreMorphicDisplay }. 'repaint the screen -- useful for removing unwanted display artifacts, lingering cursors, etc.' }. nil}. Preferences simpleMenus ifFalse: [self fillIn: menu from: { {'open...' . { self . #openWindow } }. {'windows...' . { self . #windowsDo } }. {'changes...' . { self . #changesDo } }}]. self fillIn: menu from: { {'help...' . { self . #helpDo }. 'puts up a menu of useful items for updating the system, determining what version you are running, and much else'}. {'appearance...' . { self . #appearanceDo }. 'put up a menu offering many controls over appearance.' }}. Preferences simpleMenus ifFalse: [self fillIn: menu from: { {'do...' . { Utilities . #offerCommonRequests} . 'put up an editible list of convenient expressions, and evaluate the one selected.' }}]. self fillIn: menu from: { nil. {'objects (o)' . { #myWorld . #activateObjectsTool } . 'A tool for finding and obtaining many kinds of objects'}. {'new morph...' . { self . #newMorph }. 'Offers a variety of ways to create new objects'}. nil. {'authoring tools...' . { self . #scriptingDo } . 'A menu of choices useful for authoring'}. {'playfield options...' . { self . #playfieldDo } . 'A menu of options pertaining to this object as viewed as a playfield' }. {'flaps...'. { self . #flapsDo } . 'A menu relating to use of flaps. For best results, use "keep this menu up"' }. {'projects...' . { self . #projectDo }. 'A menu of commands relating to use of projects' }}. Preferences simpleMenus ifFalse: [self fillIn: menu from: { {'print PS to file...' . { self . #printWorldOnFile } . 'write the world into a postscript file'}. {'debug...' . { self . #debugDo } . 'a menu of debugging items' }}]. self fillIn: menu from: { nil. {'save' . { self . #saveSession } . 'save the current version of the image on disk' }. {'save as...' . { Smalltalk . #saveAs }. 'save the current version of the image on disk under a new name.'}. {'save as new version' . { Smalltalk . #saveAsNewVersion }. 'give the current image a new version-stamped name and save it under that name on disk.' }. {'save and quit' . { self . #saveAndQuit } . 'save the current image on disk, and quit out of Squeak.'}. {'quit' . { self . #quitSession } . 'quit out of Squeak.' }}. ^ menu! ! !TileMorph methodsFor: 'misc' stamp: 'sw 11/27/2001 12:24'! addCustomMenuItems: aMenu hand: aHandMorph "Add custom halo menu items to a menu" | aPlayer | super addCustomMenuItems: aMenu hand: aHandMorph. ((aPlayer _ self associatedPlayer) notNil and: [aPlayer costume isMorph]) ifTrue: [aMenu addLine. aMenu add: 'hand me this object' target: self action: #handReferentMorph. aMenu balloonTextForLastItem: 'This tile refers to an actual graphical object; use this menu item to grab that object. Caution!! This may remove the object from a place it really ought to stay.'. aMenu addLine ]! ! !ViewerFlapTab methodsFor: 'menu' stamp: 'sw 11/27/2001 14:27'! addCustomMenuItems: aMenu hand: aHandMorph "Add further items to the menu as appropriate. NB: Cannot call super here." aMenu add: 'flap color...' target: self action: #changeFlapColor. aMenu addLine. aMenu addUpdating: #edgeString action: #setEdgeToAdhereTo. aMenu addUpdating: #dragoverString action: #toggleDragOverBehavior. aMenu addUpdating: #mouseoverString action: #toggleMouseOverBehavior. aMenu addLine. aMenu addUpdating: #compactFlapString target: self action: #changeCompactFlap. aMenu add: 'destroy this flap' action: #destroyFlap! ! !ZASMCameraMarkMorph methodsFor: 'menu' stamp: 'sw 11/27/2001 12:20'! addCustomMenuItems: aMenu hand: aHandMorph "Add custom halo menu items" aMenu add: 'Go to this mark' target: self action: #gotoMark. aMenu add: 'Set transition' target: self action: #setTransition. super addCustomMenuItems: aMenu hand: aHandMorph ! ! !ZASMCameraMarkMorph methodsFor: 'menu' stamp: 'sw 11/27/2001 14:58'! setTransition "Set the transition" ^ self setTransition: ActiveEvent! ! ZASMCameraMarkMorph removeSelector: #addAddHandMenuItemsForHalo:hand:! WireMorph removeSelector: #addAddHandMenuItemsForHalo:hand:! ViewerFlapTab removeSelector: #addAddHandMenuItemsForHalo:hand:! TileMorph removeSelector: #addAddHandMenuItemsForHalo:hand:! SketchMorph removeSelector: #addToggleItemsTo:hand:! SelectionMorph removeSelector: #addAddHandMenuItemsForHalo:hand:! PluggableListMorph removeSelector: #addAddHandMenuItemsForHalo:hand:! Component removeSelector: #addAddHandMenuItemsForHalo:hand:! Player removeSelector: #borderStyleForSymbol:! PhraseTileMorph removeSelector: #addAddHandMenuItemsForHalo:hand:! PasteUpMorph removeSelector: #addAddHandMenuItemsForHalo:hand:! ObjectsTool removeSelector: #addAddHandMenuItemsForHalo:hand:! ObjectsTool removeSelector: #addCustomHaloMenuItems:hand:! FunctionComponent removeSelector: #addAddHandMenuItemsForHalo:hand:! FunctionComponent removeSelector: #addCustomHaloMenuItems:hand:! FlapTab removeSelector: #addAddHandMenuItemsForHalo:hand:! ComponentLikeModel removeSelector: #addAddHandMenuItemsForHalo:hand:! BorderedMorph removeSelector: #addCustomMenuItems:hand:! Morph removeSelector: #addToggeItemsToHaloMenu:! Morph removeSelector: #addWorldHaloMenuItemsTo:hand:!