Etoys: Etoys-Richo.106.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

Etoys: Etoys-Richo.106.mcz

commits-2
Ricardo Moran uploaded a new version of Etoys to project Etoys:
http://source.squeak.org/etoys/Etoys-Richo.106.mcz

==================== Summary ====================

Name: Etoys-Richo.106
Author: Richo
Time: 15 February 2012, 5:08:02 pm
UUID: 87396860-3791-2e48-93ab-1f080fac9474
Ancestors: Etoys-Richo.105, Etoys-kfr.105

* Added a new dialog for adding/modifying user slots.

=============== Diff against Etoys-kfr.105 ===============

Item was added:
+ NewVariableDialogMorph subclass: #ModifyVariableDialogMorph
+ instanceVariableNames: 'slot'
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Etoys-Scripting'!

Item was added:
+ ----- Method: ModifyVariableDialogMorph class>>on:slot: (in category 'as yet unclassified') -----
+ on: aMorph slot: aByteSymbol
+ ^ self basicNew initializeWith: aMorph slot: aByteSymbol!

Item was added:
+ ----- Method: ModifyVariableDialogMorph>>doAccept (in category 'actions') -----
+ doAccept
+ | newName |
+ self delete.
+ self varName isEmpty ifTrue: [^ self].
+ "If the original slot was modified while this dialog was still open, we add a new variable"
+ (self targetPlayer slotInfo includesKey: slot)
+ ifFalse: [self addNewVariable.
+ ^ self].
+ "Change slot type"
+ self varType = (self targetPlayer typeForSlot: slot)
+ ifFalse: [self targetPlayer
+ changeSlotTypeOf: slot
+ to: self varType].
+ "Change slot name"
+ (newName := self varAcceptableName) = slot
+ ifFalse: [self targetPlayer
+ renameSlot: slot
+ newSlotName: newName].
+ "Change decimal places"
+ (#(#Number #Point) includes: self varType)
+ ifTrue: [
+ self targetPlayer
+ setPrecisionFor: newName
+ precision: self decimalPlaces]!

Item was added:
+ ----- Method: ModifyVariableDialogMorph>>initializeWith:slot: (in category 'initialization') -----
+ initializeWith: aMorph slot: aSymbolOrNil
+ myTarget := aMorph.
+ slot := aSymbolOrNil.
+ self initialize!

Item was added:
+ ----- Method: ModifyVariableDialogMorph>>title (in category 'accessing') -----
+ title
+ ^ 'Modify variable'!

Item was added:
+ ----- Method: ModifyVariableDialogMorph>>varAcceptableName (in category 'accessing') -----
+ varAcceptableName
+ ^ ScriptingSystem
+ acceptableSlotNameFrom: self varName
+ forSlotCurrentlyNamed: slot
+ asSlotNameIn: self targetPlayer
+ world: self targetPlayer costume world!

Item was added:
+ ----- Method: ModifyVariableDialogMorph>>varName (in category 'accessing') -----
+ varName
+ ^ varNameText
+ ifNil: [slot]
+ ifNotNil: [:text | text contents string]!

Item was added:
+ ----- Method: ModifyVariableDialogMorph>>varType (in category 'accessing') -----
+ varType
+ ^ varTypeButton
+ ifNil: [self targetPlayer typeForSlot: slot]
+ ifNotNil: [:button|
+ Vocabulary typeChoices
+ detect: [:each |
+ each translated = button label]
+ ifNone: [button label asSymbol]]!

Item was added:
+ GenericPropertiesMorph subclass: #NewVariableDialogMorph
+ instanceVariableNames: 'varNameText varTypeButton decimalPlacesButton'
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Etoys-Scripting'!

Item was added:
+ ----- Method: NewVariableDialogMorph class>>new (in category 'as yet unclassified') -----
+ new
+ ^ self on: Morph new openInWorld!

Item was added:
+ ----- Method: NewVariableDialogMorph class>>on: (in category 'as yet unclassified') -----
+ on: morph
+ ^ self basicNew initializeWith: morph!

Item was added:
+ ----- Method: NewVariableDialogMorph>>addArrowsOn: (in category 'build') -----
+ addArrowsOn: button
+ | arrowsHolder |
+ arrowsHolder := (TileMorph addArrowsOn: button) anyOne owner.
+ arrowsHolder center: button left + (arrowsHolder width / 2) + 2 @ button center y.
+ !

Item was added:
+ ----- Method: NewVariableDialogMorph>>addDecimalPlaces (in category 'build') -----
+ addDecimalPlaces
+ self addARow: {
+ self inAColumn: {
+ (self addARow: {
+ self lockedString: 'Decimal places: ' translated.
+ self spacer.
+ decimalPlacesButton := self buildDecimalPlacesButton
+ }) cellPositioning: #center.
+ }
+ }.
+ self addSeparator!

Item was added:
+ ----- Method: NewVariableDialogMorph>>addNewVariable (in category 'actions') -----
+ addNewVariable
+ | slotName |
+ self targetPlayer
+ addInstanceVariableNamed: (slotName := self varAcceptableName)
+ type: self varType
+ value: (self targetPlayer initialValueForSlotOfType: self varType).
+ (#(#Number #Point) includes: self varType)
+ ifTrue: [
+ self targetPlayer
+ setPrecisionFor: slotName
+ precision: self decimalPlaces]!

Item was added:
+ ----- Method: NewVariableDialogMorph>>addSeparator (in category 'build') -----
+ addSeparator
+ (self addAColumn: {})
+ wrapCentering: #topLeft;
+ color: Color white;
+ borderWidth: 2;
+ borderColor: self color darker.!

Item was added:
+ ----- Method: NewVariableDialogMorph>>askUserForDecimalPlaces (in category 'actions') -----
+ askUserForDecimalPlaces
+ | list |
+ list := #(0 1 2 3 4 5 6 7 8 9 10).
+ ^ UIManager
+ chooseFrom: (list collect: [:each | each asString])
+ values: list
+ title: ('How many decimal places? (currently {1})' translated
+ format: {self decimalPlaces})!

Item was added:
+ ----- Method: NewVariableDialogMorph>>askUserForNewType (in category 'actions') -----
+ askUserForNewType
+ | typeChoices menuTitle |
+ typeChoices := Vocabulary typeChoices asOrderedCollection.
+ [self target renderedMorph defaultPatch]
+ on:Exception
+ do:[ typeChoices remove: #Patch ifAbsent: [typeChoices]].
+ menuTitle := 'Choose the TYPE
+ for {1}
+ ' translated, '
+ (currently {2})' translated format: {self varAcceptableName. self varType}.
+ ^ UIManager
+ chooseFrom: (typeChoices collect: [:t | t translated])
+ values: typeChoices
+ title: menuTitle!

Item was added:
+ ----- Method: NewVariableDialogMorph>>buildDecimalPlacesButton (in category 'build') -----
+ buildDecimalPlacesButton
+ | button |
+ button := SimpleButtonMorph new
+ labelString: self decimalPlaces asString font: Preferences standardEToysButtonFont;
+ color: (Color r: 0.806 g: 1.0 b: 0.645);
+ target: self;
+ actionSelector: #chooseDecimalPlaces;
+ extent: 200 @ (TextStyle defaultFont height + 10);
+ cornerStyle: #square;
+ borderColor: #raised;
+ yourself.
+ self addArrowsOn: button.
+ ^ button
+ !

Item was added:
+ ----- Method: NewVariableDialogMorph>>buildVarTypeButton (in category 'build') -----
+ buildVarTypeButton
+ | button |
+ button := SimpleButtonMorph new
+ labelString: self varType translated font: Preferences standardEToysButtonFont;
+ color: (Color r: 0.806 g: 1.0 b: 0.645);
+ target: self;
+ actionSelector: #chooseType;
+ extent: 200 @ (TextStyle defaultFont height + 10);
+ cornerStyle: #square;
+ borderColor: #raised;
+ yourself.
+ self addArrowsOn: button.
+ ^ button
+ !

Item was added:
+ ----- Method: NewVariableDialogMorph>>chooseDecimalPlaces (in category 'actions') -----
+ chooseDecimalPlaces
+ self askUserForDecimalPlaces
+ ifNotNil: [:reply |
+ decimalPlacesButton label: reply asString.
+ self rebuild]!

Item was added:
+ ----- Method: NewVariableDialogMorph>>chooseType (in category 'actions') -----
+ chooseType
+ self askUserForNewType
+ ifNotNil: [:newType |
+ varTypeButton label: newType.
+ self rebuild]!

Item was added:
+ ----- Method: NewVariableDialogMorph>>decimalPlaces (in category 'accessing') -----
+ decimalPlaces
+ ^ decimalPlacesButton
+ ifNil: [Utilities
+ decimalPlacesForFloatPrecision: (self targetPlayer
+ defaultFloatPrecisionFor: (Utilities getterSelectorFor: self varAcceptableName))]
+ ifNotNil: [:button| button label asNumber]!

Item was added:
+ ----- Method: NewVariableDialogMorph>>defaultBorderColor (in category 'accessing') -----
+ defaultBorderColor
+ ^ self defaultColor darker!

Item was added:
+ ----- Method: NewVariableDialogMorph>>defaultColor (in category 'accessing') -----
+ defaultColor
+ ^ (Color r: 0.677 g: 0.935 b: 0.484)
+ mixed: 0.9 with: Color blue!

Item was added:
+ ----- Method: NewVariableDialogMorph>>doAccept (in category 'actions') -----
+ doAccept
+ self delete.
+ self varName isEmpty ifTrue: [^ self].
+ self addNewVariable!

Item was added:
+ ----- Method: NewVariableDialogMorph>>initialize (in category 'initialize') -----
+ initialize
+ super initialize.
+ self rebuild!

Item was added:
+ ----- Method: NewVariableDialogMorph>>initializeWith: (in category 'initialize') -----
+ initializeWith: aMorph
+ myTarget := aMorph.
+ self initialize!

Item was added:
+ ----- Method: NewVariableDialogMorph>>morphicLayerNumber (in category 'accessing') -----
+ morphicLayerNumber
+
+ ^10.6!

Item was added:
+ ----- Method: NewVariableDialogMorph>>newTextMorph (in category 'build') -----
+ newTextMorph
+ ^ TextMorph new autoFit: false;
+ extent: 200 @ (TextStyle defaultFont height + 6);
+ borderWidth: 1;
+ backgroundColor: Color white;
+ borderColor: Color gray;
+ centered!

Item was added:
+ ----- Method: NewVariableDialogMorph>>rebuild (in category 'build') -----
+ rebuild
+ | buttonColor |
+ self removeAllMorphs.
+ self addAColumn: {
+ self lockedString: self title translated.
+ }.
+ self addSeparator.
+
+ self addARow: {
+ self inAColumn: {
+ (self addARow: {
+ self lockedString: 'Name: ' translated.
+ self spacer.
+ varNameText := self newTextMorph
+ contentsWrapped: self varName;
+ selectAll;
+ crAction: (MessageSend
+ receiver: self
+ selector: #doAccept);
+ yourself
+ }) cellPositioning: #center.
+ (self addARow: {
+ self lockedString: 'Type: ' translated.
+ self spacer.
+ varTypeButton := self buildVarTypeButton
+ }) cellPositioning: #center.
+ }
+ }.
+ ActiveWorld activeHand newKeyboardFocus: varNameText.
+ self addSeparator.
+
+ (#(#Number #Point) includes: self varType)
+ ifTrue: [self addDecimalPlaces].
+
+ buttonColor := self color lighter.
+ self addARow: {
+ self inAColumn: {
+ (self addARow: {
+ self
+ buttonNamed: 'Accept' translated action: #doAccept color: buttonColor
+ help: 'keep changes made and close panel' translated.
+ self
+ buttonNamed: 'Cancel' translated action: #doCancel color: buttonColor
+ help: 'cancel changes made and close panel' translated.
+ }) listCentering: #center
+ }
+ }
+ !

Item was added:
+ ----- Method: NewVariableDialogMorph>>spacer (in category 'build') -----
+ spacer
+ ^ AlignmentMorph newVariableTransparentSpacer !

Item was added:
+ ----- Method: NewVariableDialogMorph>>target (in category 'accessing') -----
+ target
+ ^ myTarget!

Item was added:
+ ----- Method: NewVariableDialogMorph>>targetPlayer (in category 'accessing') -----
+ targetPlayer
+ ^ self target assuredPlayer!

Item was added:
+ ----- Method: NewVariableDialogMorph>>title (in category 'accessing') -----
+ title
+ ^ 'Add new variable'!

Item was added:
+ ----- Method: NewVariableDialogMorph>>varAcceptableName (in category 'accessing') -----
+ varAcceptableName
+ ^ ScriptingSystem
+ acceptableSlotNameFrom: self varName
+ forSlotCurrentlyNamed: nil
+ asSlotNameIn: self targetPlayer
+ world: self targetPlayer costume world!

Item was added:
+ ----- Method: NewVariableDialogMorph>>varName (in category 'accessing') -----
+ varName
+ ^ varNameText
+ ifNil: [| usedNames |
+ usedNames := self targetPlayer class instVarNames.
+ Utilities
+ keyLike: ('var' translated, (usedNames size + 1) asString)
+ satisfying: [:aKey | (usedNames includes: aKey) not]]
+ ifNotNil: [:text | text contents string]!

Item was added:
+ ----- Method: NewVariableDialogMorph>>varType (in category 'accessing') -----
+ varType
+ ^ varTypeButton
+ ifNil: [self targetPlayer initialTypeForSlotNamed: self varAcceptableName]
+ ifNotNil: [:button|
+ Vocabulary typeChoices
+ detect: [:each |
+ each translated = button label]
+ ifNone: [button label asSymbol]]!

Item was changed:
  ----- Method: Player>>addInstanceVariable (in category 'slots-user') -----
  addInstanceVariable
  "Offer the user the opportunity to add an instance variable, and if he goes through with it, actually add it."
+ ActiveWorld
+ addMorphInLayer: (NewVariableDialogMorph on: self costume)
+ centeredNear: (ActiveHand ifNil:[Sensor]) cursorPoint!
-
- | itsName initialValue typeChosen usedNames initialAnswer setterSelector originalString |
- usedNames := self class instVarNames.
-
- initialAnswer := Utilities keyLike: ('var' translated, (usedNames size + 1) asString)  satisfying: [:aKey | (usedNames includes: aKey) not].
-
- originalString := FillInTheBlank request: 'name for new variable: ' translated initialAnswer: initialAnswer.
- Cursor wait showWhile: [
- originalString isEmptyOrNil ifTrue: [^ self].
- itsName := ScriptingSystem acceptableSlotNameFrom: originalString forSlotCurrentlyNamed: nil asSlotNameIn: self world: self costume world.
-
-   itsName size == 0 ifTrue: [^ self].
- self assureUniClass.
- typeChosen := (self askUserForNewTypeFor: itsName) ifNil: [#Number].
- self slotInfo at: itsName put: (SlotInformation new initialize type: typeChosen).
- initialValue := self initialValueForSlotOfType: typeChosen.
- self addInstanceVarNamed: itsName withValue: initialValue.
- self compileInstVarAccessorsFor: itsName.
- setterSelector := Utilities setterSelectorFor: itsName.
- ((self class allSubInstances copyWithout: self) reject: [:e | e isSequentialStub]) do:
- [:anInstance | anInstance perform: setterSelector with: initialValue].
- self regenerateScripts.
- self updateAllViewersAndForceToShow: ScriptingSystem nameForInstanceVariablesCategory.
- ]!

Item was changed:
  ----- Method: Player>>addInstanceVariableNamed:type:value: (in category 'slots-user') -----
  addInstanceVariableNamed: nameSymbol type: typeChosen value: aValue
  "Add an instance variable of the given name and type, and initialize it to have the given value"
 
  | initialValue setterSelector |
  self assureUniClass.
  self slotInfo at: nameSymbol put: (SlotInformation new initialize type: typeChosen).
+ initialValue := self initialValueForSlotOfType: typeChosen.
- initialValue _ self initialValueForSlotOfType: typeChosen.
  self addInstanceVarNamed: nameSymbol withValue: aValue.
+ self compileInstVarAccessorsFor: nameSymbol.
- self class compileAccessorsFor: nameSymbol.
  setterSelector _ Utilities setterSelectorFor: nameSymbol.
+ ((self class allSubInstances copyWithout: self) reject: [:e | e isSequentialStub]) do:
- (self class allSubInstances copyWithout: self) do:
  [:anInstance | anInstance perform: setterSelector with: initialValue].
  self regenerateScripts.
  self updateAllViewersAndForceToShow: ScriptingSystem nameForInstanceVariablesCategory
  !

Item was removed:
- ----- Method: Player>>askUserForNewTypeFor: (in category 'slots-user') -----
- askUserForNewTypeFor: slotName
- | typeChoices menuCaption |
- typeChoices := Vocabulary typeChoices asOrderedCollection.
- [self costume renderedMorph defaultPatch]
- on:Exception
- do:[ typeChoices remove: #Patch ifAbsent: [typeChoices]].
- menuCaption := 'Choose the TYPE
- for {1}
- ' translated, slotName, '
- (currently {2})' translated format: {slotName. (self slotInfoAt: slotName) type translated}.
- ^ (SelectionMenu
- labelList: (typeChoices collect: [:t | t translated])
- lines: #()
- selections: typeChoices)
- startUpWithCaption: menuCaption.!

Item was added:
+ ----- Method: Player>>changeSlotInfo: (in category 'slots-user') -----
+ changeSlotInfo: aByteSymbol
+ ActiveWorld
+ addMorphInLayer: (ModifyVariableDialogMorph on: self costume slot: aByteSymbol)
+ centeredNear: (ActiveHand ifNil:[Sensor]) cursorPoint!

Item was added:
+ ----- Method: Player>>changeSlotTypeOf:to: (in category 'slots-user') -----
+ changeSlotTypeOf: slotName to: newType
+ (self typeForSlot: slotName) capitalized = newType ifTrue: [^ self].
+
+ (self slotInfoAt: slotName) type: newType.
+ self class allInstancesDo:   "allSubInstancesDo:"
+ [:anInst | anInst instVarNamed: slotName asString put:
+ (anInst valueOfType: newType from: (anInst instVarNamed: slotName))].
+ self updateAllViewers. "does siblings too"
+ self changeTypesInWatchersOf: slotName.  "does siblings too"
+
+ !

Item was removed:
- ----- Method: Player>>chooseSlotTypeFor: (in category 'slots-user') -----
- chooseSlotTypeFor: aGetter
- "Let the user designate a type for the slot associated with the given getter"
-
- | typeChosen slotName |
- slotName := Utilities inherentSelectorForGetter: aGetter.
- typeChosen := self askUserForNewTypeFor: slotName.
- typeChosen isEmptyOrNil ifTrue: [^ self].
- (self typeForSlot: slotName) capitalized = typeChosen ifTrue: [^ self].
-
- (self slotInfoAt: slotName) type: typeChosen.
- self class allInstancesDo:   "allSubInstancesDo:"
- [:anInst | anInst instVarNamed: slotName asString put:
- (anInst valueOfType: typeChosen from: (anInst instVarNamed: slotName))].
- self updateAllViewers. "does siblings too"
- self changeTypesInWatchersOf: slotName.  "does siblings too"
-
- !

Item was removed:
- ----- Method: Player>>renameSlot: (in category 'slots-user') -----
- renameSlot: oldSlotName
- | reply newSlotName |
- reply := FillInTheBlank request: 'New name for "' translated , oldSlotName , '":'
- initialAnswer: oldSlotName.
- reply isEmpty ifTrue: [^self].
- newSlotName := ScriptingSystem
- acceptableSlotNameFrom: reply
- forSlotCurrentlyNamed: oldSlotName
- asSlotNameIn: self
- world: self costume currentWorld.
- oldSlotName = newSlotName ifTrue: [^ self].
- self renameSlot: oldSlotName newSlotName: newSlotName!

Item was changed:
  ----- Method: Player>>setPrecisionFor: (in category 'slots-user') -----
  setPrecisionFor: slotName
  "Set the precision for the given slot name"
 
+ | aList aMenu reply aGetter places |
- | aList aMenu reply val aGetter places |
  aGetter := Utilities getterSelectorFor: slotName.
  places := Utilities
  decimalPlacesForFloatPrecision: (self defaultFloatPrecisionFor: aGetter).
  aList := #('0' '1' '2' '3' '4' '5' '6' '7' '8' '9' '10').
  aMenu := SelectionMenu labels: aList
  selections: (aList collect: [:m | m asNumber]).
  reply := aMenu
  startUpWithCaption: ('How many decimal places? (currently {1})' translated
  format: {places}).
  reply ifNotNil:
+ [self setPrecisionFor: slotName precision: reply]!
- [(self slotInfo includesKey: slotName)
- ifTrue:
- ["it's a user slot"
-
- (self slotInfoAt: slotName)
- floatPrecision: (Utilities floatPrecisionForDecimalPlaces: reply).
- self class allInstancesDo:
- [:anInst |
- reply == 0
- ifFalse:
- [((val := anInst instVarNamed: slotName asString) isInteger)
- ifTrue: [anInst instVarNamed: slotName asString put: val asFloat]].
- anInst updateAllViewers]]
- ifFalse:
- ["it's specifying a preference for precision on a system-defined numeric slot"
-
- self noteDecimalPlaces: reply forGetter: aGetter.
- self updateAllViewers]]!

Item was added:
+ ----- Method: Player>>setPrecisionFor:precision: (in category 'slots-user') -----
+ setPrecisionFor: slotName precision: aNumber
+ | val |
+ (self slotInfo includesKey: slotName)
+ ifTrue:
+ ["it's a user slot"
+
+ (self slotInfoAt: slotName)
+ floatPrecision: (Utilities floatPrecisionForDecimalPlaces: aNumber).
+ self class allInstancesDo:
+ [:anInst |
+ aNumber == 0
+ ifFalse:
+ [((val := anInst instVarNamed: slotName asString) isInteger)
+ ifTrue: [anInst instVarNamed: slotName asString put: val asFloat]].
+ anInst updateAllViewers]]
+ ifFalse:
+ ["it's specifying a preference for precision on a system-defined numeric slot"
+
+ self noteDecimalPlaces: aNumber forGetter: (Utilities getterSelectorFor: slotName).
+ self updateAllViewers]!

Item was changed:
  ----- Method: Player>>slotInfoButtonHitFor:inViewer: (in category 'scripts-kernel') -----
  slotInfoButtonHitFor: aGetterSymbol inViewer: aViewer
  "The user made a gesture asking for slot menu for the given getter symbol in a viewer; put up the menu."
 
  | aMenu slotSym aType typeVocab interface selector |
 
  (#(+ - * /) includes: aGetterSymbol)
  ifTrue:
  [^ self inform: ('{1} is used for vector operations' translated format: {aGetterSymbol})].
 
  slotSym _ Utilities inherentSelectorForGetter: aGetterSymbol.
  aType _ self typeForSlotWithGetter: aGetterSymbol asSymbol.
  aMenu _ MenuMorph new defaultTarget: self.
  interface := aViewer currentVocabulary methodInterfaceAt: aGetterSymbol ifAbsent: [nil].
  selector := interface isNil
  ifTrue: [slotSym asString]
  ifFalse: [interface selector].
 
  aType = #Patch ifTrue: [
  aMenu add: 'grab morph' translated
  target: (self perform: aGetterSymbol)
  selector: #grabPatchMorph
  argument: #().
  aMenu addLine.
  ].
 
  (typeVocab _ Vocabulary vocabularyForType: aType) addWatcherItemsToMenu: aMenu forGetter: aGetterSymbol.
 
  (self slotInfo includesKey: slotSym)
  ifTrue:
+ [typeVocab addUserSlotItemsTo: aMenu slotSymbol: slotSym.
- [aMenu add: 'change value type' translated selector: #chooseSlotTypeFor: argument: aGetterSymbol.
- typeVocab addUserSlotItemsTo: aMenu slotSymbol: slotSym.
  aMenu add: ('remove "{1}"' translated format: {slotSym}) selector: #removeSlotNamed: argument: slotSym.
+ aMenu add: ('modify "{1}"' translated format: {slotSym}) selector: #changeSlotInfo: argument: slotSym
+ ]
+ ifFalse: [
+ aMenu addLine.
+ typeVocab addExtraItemsToMenu: aMenu forSlotSymbol: slotSym.  "e.g. Player type adds hand-me-tiles"].
- aMenu add: ('rename "{1}"' translated format: {slotSym}) selector: #renameSlot: argument: slotSym. aMenu addLine].
 
- typeVocab addExtraItemsToMenu: aMenu forSlotSymbol: slotSym.  "e.g. Player type adds hand-me-tiles"
-
  self addIdiosyncraticMenuItemsTo: aMenu forSlotSymol: slotSym.
 
  aMenu items isEmpty ifTrue:
  [aMenu add: 'ok' translated action: #yourself].
 
  aMenu popUpForHand: aViewer primaryHand in: aViewer world!

_______________________________________________
etoys-dev mailing list
[hidden email]
http://lists.squeakland.org/mailman/listinfo/etoys-dev