A new version of Morphic was added to project The Inbox:
http://source.squeak.org/inbox/Morphic-kfr.1620.mcz
==================== Summary ====================
Name: Morphic-kfr.1620
Author: kfr
Time: 4 February 2020, 5:55:31.268512 pm
UUID: 741c35fd-d7ac-e54b-9199-ed1dda9e4df9
Ancestors: Morphic-kfr.1619
Enhancement for PolygonMorph. When a vertex is dropped it will snap if it is close to another PolygonMorphs vertex. It is possible to toggle functionality on/ off in menu
=============== Diff against Morphic-kfr.1619 ===============
Item was changed:
BorderedMorph subclass: #PolygonMorph
+ instanceVariableNames: 'vertices closed filledForm arrows arrowForms smoothCurve curveState borderDashSpec handles borderForm snapToOtherPolygons'
- instanceVariableNames: 'vertices closed filledForm arrows arrowForms smoothCurve curveState borderDashSpec handles borderForm'
classVariableNames: ''
poolDictionaries: ''
category: 'Morphic-Basic'!
!PolygonMorph commentStamp: 'md 2/24/2006 20:34' prior: 0!
This class implements a morph which can behave as four different objects depending on the the following two facts:
- is it OPEN or CLOSED?
- is it SEGMENTED or SMOOTHED.
1. The OPEN and SEGMENTED variant looks like polyline.
2. The OPEN and SMOOTHED variant looks like spline (kind of curve)
3. The CLOSED and SEGMENTED variant looks like polygon. This is actually what you get when you do
PolygonMorph new openInWorld
You get a triangle. See below how to manipulate these objects...
4. The CLOSED and SMOOTHED variant looks like blob (???)
Prototypes of this morph can also be found in "Object Catalog". Several (different variants) of this object are among "Basic" morphs.
Explore the assiciated morph-menu. It enables you
- to toggle showing of "handles". They make it possible to
- reposition already existing vertices (by moving yellow handles)
- create new vertices (by moving green handles)
- delete already existing vertices (by dragging and dropping one yellow handle closely
nearby the adjacent yellow handle
Handles can be made visible/hidden by shift+leftclicking the morph. This way it is possible
to quickly show handles, adjust vertices and then again hide handles.
- making closed polygon open, i.e. converting it to a curve (and vice versa)
- toggle smoothed/segmented line/outline
- set up custom dashing (for line, curves or borders of closed polygons
- set up custom arrow-heads (for lines resp. curves)
------------------------------------------------------------------------------------------
Implementation notes:
This class combines the old Polygon and Curve classes.
The 1-bit fillForm to make display and containment tests reasonably fast. However, this functionality is in the process of being supplanted by balloon capabilities, which should eventually provide anti-aliasing as well.
wiz 7/18/2004 21:26
s have made some changes to this class to
1) correct some bugs associated with one vertex polygons.
2) prepare for some enhancements with new curves.
3) add shaping items to menu.!
Item was changed:
----- Method: PolygonMorph>>addCustomMenuItems:hand: (in category 'menu') -----
addCustomMenuItems: aMenu 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."
super addCustomMenuItems: aMenu hand: aHandMorph.
aMenu addUpdating: #handlesShowingPhrase target: self action: #showOrHideHandles.
vertices size > 2 ifTrue:
[aMenu addUpdating: #openOrClosePhrase target: self action: #makeOpenOrClosed].
aMenu addUpdating: #smoothPhrase target: self action: #toggleSmoothing.
+ aMenu addUpdating: #snapToOtherPolygonPhrase target: self action: #toggleSnapToOtherPolygons.
aMenu addLine.
aMenu add: 'specify dashed line' translated action: #specifyDashedLine.
self isOpen ifTrue:
[aMenu addLine.
aMenu addWithLabel: '---' enablement: [self isOpen and: [arrows ~~ #none]] action: #makeNoArrows.
aMenu addWithLabel: '-->' enablement: [self isOpen and: [arrows ~~ #forward]] action: #makeForwardArrow.
aMenu addWithLabel: '<--' enablement: [self isOpen and: [arrows ~~ #back]] action: #makeBackArrow.
aMenu addWithLabel: '<->' enablement: [self isOpen and: [arrows ~~ #both]] action: #makeBothArrows.
aMenu add: 'customize arrows' translated action: #customizeArrows:.
(self hasProperty: #arrowSpec)
ifTrue: [aMenu add: 'standard arrows' translated action: #standardArrows]].!
Item was changed:
----- Method: PolygonMorph>>dropVertex:event:fromHandle: (in category 'editing') -----
+ dropVertex: ix event: evt fromHandle: handle
+ "Leave vertex in new position. If dropped ontop another vertex delete
+ this one.
- dropVertex: ix event: evt fromHandle: handle
- "Leave vertex in new position. If dropped ontop another vertex delete this one.
Check for too few vertices before deleting. The alternative
+ is not pretty -wiz"
+ | p world |
- is not pretty -wiz"
- | p |
p := vertices at: ix.
+
+ "snap the dropped vertex to a vertex of another PolygonMorph if it is in near proximity"
+ self isSnappingToOtherPolygons
+ ifTrue: [world := Project current world.
+ world submorphs
+ do: [:each | ((each respondsTo: #vertices)
+ and: [each ~= self])
+ ifTrue: [each vertices
+ do: [:otherMorphsVertex | (otherMorphsVertex dist: p)
+ < 3
+ ifTrue: [vertices at: ix put: otherMorphsVertex]]]]].
(vertices size >= 2
and: ["check for too few vertices before deleting. The alternative
is not pretty -wiz"
((vertices atWrap: ix - 1)
dist: p)
< 3
or: [((vertices atWrap: ix + 1)
dist: p)
< 3]])
ifTrue: ["Drag a vertex onto its neighbor means delete"
+ self deleteVertexAt: ix].
- self deleteVertexAt: ix .].
evt shiftPressed
ifTrue: [self removeHandles]
ifFalse: [self addHandles
"remove then add to recreate"]!
Item was changed:
----- Method: PolygonMorph>>initialize (in category 'initialization') -----
initialize
"initialize the state of the receiver"
super initialize.
""
vertices := Array
with: 5 @ 0
with: 20 @ 10
with: 0 @ 20.
closed := true.
smoothCurve := false.
arrows := #none.
+ snapToOtherPolygons := false.
self computeBounds!
Item was added:
+ ----- Method: PolygonMorph>>isSnappingToOtherPolygons (in category 'access') -----
+ isSnappingToOtherPolygons
+ ^snapToOtherPolygons ifNil:[ snapToOtherPolygons := false].
+ !
Item was added:
+ ----- Method: PolygonMorph>>toggleSnapToOtherPolygons (in category 'menu') -----
+ toggleSnapToOtherPolygons
+ ^snapToOtherPolygons := snapToOtherPolygons not!
Christoph Thiede uploaded a new version of Monticello to project The Inbox:
http://source.squeak.org/inbox/Monticello-ct.714.mcz
==================== Summary ====================
Name: Monticello-ct.714
Author: ct
Time: 5 February 2020, 11:17:45.064675 am
UUID: 2b7c2ae8-c1b1-bb48-aec2-f4a6d03f6507
Ancestors: Monticello-cmm.708
Improves multilingual support for loading progress notifications.
=============== Diff against Monticello-cmm.708 ===============
Item was changed:
----- Method: MCPackageLoader>>basicLoad (in category 'private') -----
basicLoad
+ "Load the contents of some package. This is the core loading method in Monticello. Be wary about modifying it unless you understand the details and dependencies of the various entities being modified."
- "Load the contents of some package. This is the core loading method
- in Monticello. Be wary about modifying it unless you understand the details
- and dependencies of the various entities being modified."
| pkgName |
errorDefinitions := OrderedCollection new.
+ "Obviously this isn't the package name but we don't have anything else to use here.
+ ChangeSet current name will generally work since a CS is usually installed prior to installation."
- "Obviously this isn't the package name but we don't have anything else
- to use here. ChangeSet current name will generally work since a CS is
- usually installed prior to installation."
pkgName := ChangeSet current name.
preamble ifNotNil: [ChangeSet current preambleString: (self preambleAsCommentNamed: pkgName)].
RecentMessages default suspendWhile: [
[CurrentReadOnlySourceFiles cacheDuring: [[
+ "Pass 1: Load everything but the methods, which are collected in methodAdditions."
- "Pass 1: Load everything but the methods, which are collected in methodAdditions."
additions do: [:ea |
ea isMethodDefinition
+ ifTrue: [methodAdditions add: ea asMethodAddition]
+ ifFalse: [[ea load] ifError: [errorDefinitions add: ea]].
+ ] displayingProgress: ('Reshaping {1}' translated format: {pkgName}).
- ifTrue:[methodAdditions add: ea asMethodAddition]
- ifFalse:[[ea load]on: Error do: [errorDefinitions add: ea]].
- ] displayingProgress: 'Reshaping ', pkgName.
"Try again any delayed definitions"
self shouldWarnAboutErrors ifTrue: [self warnAboutErrors].
errorDefinitions do: [:ea | ea load]
+ displayingProgress: ('Reloading {1}' translated format: {pkgName}).
- displayingProgress: 'Reloading ', pkgName.
"Pass 2: We compile new / changed methods"
+ methodAdditions do: [:ea | ea createCompiledMethod]
+ displayingProgress: ('Compiling {1}' translated format: {pkgName}).
- methodAdditions do:[:ea| ea createCompiledMethod]
- displayingProgress: 'Compiling ', pkgName.
+ 'Installing ', pkgName displayProgressFrom: 0 to: 2 during: [:bar |
+ "There is no progress *during* installation since a progress bar update will redraw the world and potentially call methods that we're just trying to install."
- 'Installing ', pkgName displayProgressFrom: 0 to: 2 during:[:bar|
- "There is no progress *during* installation since a progress bar update
- will redraw the world and potentially call methods that we're just trying to install."
bar value: 1.
+ "Pass 3: Install the new / changed methods (this is a separate pass to allow compiler changes to be loaded)"
+ methodAdditions do: [:ea | ea installMethod].
- "Pass 3: Install the new / changed methods
- (this is a separate pass to allow compiler changes to be loaded)"
- methodAdditions do:[:ea| ea installMethod].
"Pass 4: Remove the obsolete methods"
+ removals do: [:ea | ea unload].
- removals do:[:ea| ea unload].
].
"Finally, notify observers for the method additions"
methodAdditions do: [:each | each notifyObservers]
+ "the message is fake but actually telling people how much time we spend in the notifications is embarrassing so lie instead"
+ displayingProgress: ('Installing {1}' translated format: {pkgName}).
- "the message is fake but actually telling people how much time we spend
- in the notifications is embarrassing so lie instead"
- displayingProgress: 'Installing ', pkgName.
additions do: [:ea | ea postloadOver: (self obsoletionFor: ea)]
+ displayingProgress: ('Initializing {1}' translated format: {pkgName}).
- displayingProgress: 'Initializing ', pkgName.
] on: InMidstOfFileinNotification do: [:n | n resume: true]
]] ensure: [self flushChangesFile]
]!
Christoph Thiede uploaded a new version of ToolBuilder-Kernel to project The Inbox:
http://source.squeak.org/inbox/ToolBuilder-Kernel-ct.138.mcz
==================== Summary ====================
Name: ToolBuilder-Kernel-ct.138
Author: ct
Time: 5 February 2020, 11:10:09.014675 am
UUID: e66248df-c727-5440-b18d-c7b7ae9f038f
Ancestors: ToolBuilder-Kernel-mt.134
Proposal: Add convenient method String >> #informUserDuring:
We could already say
'Squeak is great!' displayProgressFrom: 9 to: 17 during: [:bar |
bar value: 9.
1 second wait.
bar value: 16.
1 seconds wait.
bar value: 17].
Now we can also say
'Squeak is great!' informUserDuring: [2 seconds wait].
=============== Diff against ToolBuilder-Kernel-mt.134 ===============
Item was changed:
+ ----- Method: String>>displayProgressAt:from:to:during: (in category '*ToolBuilder-Kernel') -----
- ----- Method: String>>displayProgressAt:from:to:during: (in category '*toolbuilder-kernel') -----
displayProgressAt: aPoint from: minVal to: maxVal during: workBlock
"Display this string as a caption over a progress bar while workBlock is evaluated.
EXAMPLE (Select next 6 lines and Do It)
'Now here''s some Real Progress'
displayProgressAt: Sensor cursorPoint
from: 0 to: 10
during: [:bar |
1 to: 10 do: [:x | bar value: x.
(Delay forMilliseconds: 500) wait]].
HOW IT WORKS (Try this in any other language :-)
Since your code (the last 2 lines in the above example) is in a block,
this method gets control to display its heading before, and clean up
the screen after, its execution.
The key, though, is that the block is supplied with an argument,
named 'bar' in the example, which will update the bar image every
it is sent the message value: x, where x is in the from:to: range.
"
^ProgressInitiationException
display: self
at: aPoint
from: minVal
to: maxVal
during: workBlock!
Item was changed:
+ ----- Method: String>>displayProgressFrom:to:during: (in category '*ToolBuilder-Kernel') -----
- ----- Method: String>>displayProgressFrom:to:during: (in category '*toolbuilder-kernel') -----
displayProgressFrom: minVal to: maxVal during: workBlock
"Display this string as a caption over a progress bar while workBlock is evaluated.
+ EXAMPLE (Select next 5 lines and Do It):
- EXAMPLE (Select next 6 lines and Do It)
'Now here''s some Real Progress'
displayProgressFrom: 0 to: 10
during: [:bar |
1 to: 10 do: [:x | bar value: x.
(Delay forMilliseconds: 500) wait]]."
^ self
displayProgressAt: nil
from: minVal
to: maxVal
during: workBlock!
Item was changed:
+ ----- Method: String>>displaySequentialProgress: (in category '*ToolBuilder-Kernel') -----
- ----- Method: String>>displaySequentialProgress: (in category '*toolbuilder-kernel') -----
displaySequentialProgress: aBlock
"
'This takes some time...' displaySequentialProgress: [
(Delay forMilliseconds: 500) wait.
ProgressNotification signal: 0.1 extra: 'just starting'.
(Delay forMilliseconds: 500) wait.
ProgressNotification signal: 0.5.
(Delay forMilliseconds: 500) wait.
ProgressNotification signal: '1.0' extra: 'done'.
(Delay forMilliseconds: 500) wait.
]
"
ProgressInitiationException
display: self
from: 0 to: 1
during: [:bar | aBlock
on: ProgressNotification
do: [:e |
bar value: e messageText asNumber.
e extraParam: self, (e extraParam ifNil: ['']).
e pass]].
!
Item was changed:
+ ----- Method: String>>edit (in category '*ToolBuilder-Kernel') -----
- ----- Method: String>>edit (in category '*toolbuilder-kernel') -----
edit
UIManager default edit: self.!
Item was changed:
+ ----- Method: String>>editWithLabel: (in category '*ToolBuilder-Kernel') -----
- ----- Method: String>>editWithLabel: (in category '*toolbuilder-kernel') -----
editWithLabel: label
UIManager default edit: self label: label!
Item was added:
+ ----- Method: String>>informUserDuring: (in category '*ToolBuilder-Kernel') -----
+ informUserDuring: aBlock
+
+ ^ Project uiManager
+ informUser: self
+ during: aBlock!
Hi all,
not sure if this issue is already present: For a few weeks, I commonly noticed some damage artifacts on my screen during a Monticello version is loaded, i. e. during a progress bar is shown. Here is an example:
[cid:01fac2bf-6f89-4ffe-8db2-6ea228a33f53]
The repository list actually has values, and after the load is complete, the list looks well again.
Are we missing any call to #changed when repositioning the progress morph?
Best,
Christoph
<http://www.hpi.de/>
Christoph Thiede uploaded a new version of Monticello to project The Inbox:
http://source.squeak.org/inbox/Monticello-ct.713.mcz
==================== Summary ====================
Name: Monticello-ct.713
Author: ct
Time: 5 February 2020, 10:59:39.500675 am
UUID: cfdf8f9d-5707-924a-958a-2f99d23bd8ef
Ancestors: Monticello-cmm.708
Refine progress display during MC loading
Don't fake a progress bar without a real value, use #informUser:during: instead.
=============== Diff against Monticello-cmm.708 ===============
Item was changed:
----- Method: MCPackageLoader>>basicLoad (in category 'private') -----
basicLoad
+ "Load the contents of some package. This is the core loading method in Monticello. Be wary about modifying it unless you understand the details and dependencies of the various entities being modified."
- "Load the contents of some package. This is the core loading method
- in Monticello. Be wary about modifying it unless you understand the details
- and dependencies of the various entities being modified."
| pkgName |
errorDefinitions := OrderedCollection new.
"Obviously this isn't the package name but we don't have anything else
to use here. ChangeSet current name will generally work since a CS is
usually installed prior to installation."
pkgName := ChangeSet current name.
preamble ifNotNil: [ChangeSet current preambleString: (self preambleAsCommentNamed: pkgName)].
RecentMessages default suspendWhile: [
[CurrentReadOnlySourceFiles cacheDuring: [[
"Pass 1: Load everything but the methods, which are collected in methodAdditions."
additions do: [:ea |
ea isMethodDefinition
+ ifTrue: [methodAdditions add: ea asMethodAddition]
+ ifFalse: [[ea load] ifError: [errorDefinitions add: ea]].
- ifTrue:[methodAdditions add: ea asMethodAddition]
- ifFalse:[[ea load]on: Error do: [errorDefinitions add: ea]].
] displayingProgress: 'Reshaping ', pkgName.
+
-
"Try again any delayed definitions"
self shouldWarnAboutErrors ifTrue: [self warnAboutErrors].
errorDefinitions do: [:ea | ea load]
displayingProgress: 'Reloading ', pkgName.
+
-
"Pass 2: We compile new / changed methods"
+ methodAdditions do: [:ea | ea createCompiledMethod]
- methodAdditions do:[:ea| ea createCompiledMethod]
displayingProgress: 'Compiling ', pkgName.
+
+ Project uiManager informUser: 'Installing ', pkgName during: [
+ "There is no progress *during* installation since a progress bar update will redraw the world and potentially call methods that we're just trying to install."
+
+ "Pass 3: Install the new / changed methods (this is a separate pass to allow compiler changes to be loaded)"
+ methodAdditions do: [:ea | ea installMethod].
+
-
- 'Installing ', pkgName displayProgressFrom: 0 to: 2 during:[:bar|
- "There is no progress *during* installation since a progress bar update
- will redraw the world and potentially call methods that we're just trying to install."
- bar value: 1.
-
- "Pass 3: Install the new / changed methods
- (this is a separate pass to allow compiler changes to be loaded)"
- methodAdditions do:[:ea| ea installMethod].
-
"Pass 4: Remove the obsolete methods"
+ removals do: [:ea | ea unload].
- removals do:[:ea| ea unload].
].
+
-
"Finally, notify observers for the method additions"
methodAdditions do: [:each | each notifyObservers]
+ "the message is fake but actually telling people how much time we spend in the notifications is embarrassing so lie instead"
- "the message is fake but actually telling people how much time we spend
- in the notifications is embarrassing so lie instead"
displayingProgress: 'Installing ', pkgName.
+
-
additions do: [:ea | ea postloadOver: (self obsoletionFor: ea)]
displayingProgress: 'Initializing ', pkgName.
+
-
] on: InMidstOfFileinNotification do: [:n | n resume: true]
]] ensure: [self flushChangesFile]
]!
Christoph Thiede uploaded a new version of Morphic to project The Inbox:
http://source.squeak.org/inbox/Morphic-ct.1624.mcz
==================== Summary ====================
Name: Morphic-ct.1624
Author: ct
Time: 5 February 2020, 10:01:38.455675 am
UUID: 232459ff-c526-a546-b734-e6b8c6366657
Ancestors: Morphic-cmm.1618
Fixes a bug when undoing dismissal of a SelectionMorph. In the past, this only restored the SelectionMorph itself but not its items.
Please note this solution is not optimal because it abuses #intoWorld:. However, I don't see any unwanted side effects at the moment ... Maybe we would like to introduce an extra hook for this in #reintroduceIntoWorld:?
=============== Diff against Morphic-cmm.1618 ===============
Item was added:
+ ----- Method: SelectionMorph>>intoWorld: (in category 'initialization') -----
+ intoWorld: aWorld
+
+ selectedItems ifNotEmpty: [
+ "Restore selected items for #reintroduceIntoWorld:"
+ selectedItems do: [:morph |
+ aWorld reintroduceIntoWorld: morph].
+ ^ self delete].
+ super intoWorld: aWorld.!
A new version of Morphic was added to project The Inbox:
http://source.squeak.org/inbox/Morphic-kfr.1620.mcz
==================== Summary ====================
Name: Morphic-kfr.1620
Author: kfr
Time: 4 February 2020, 7:54:13.845512 pm
UUID: 46cde71b-c555-574f-bd14-67b5aed4e62a
Ancestors: Morphic-kfr.1619
Enhancement for PolygonMorph. When a vertex is dropped it will snap if it is close to another PolygonMorphs vertex. It is possible to toggle functionality on/ off in menu
=============== Diff against Morphic-kfr.1619 ===============
Item was changed:
BorderedMorph subclass: #PolygonMorph
+ instanceVariableNames: 'vertices closed filledForm arrows arrowForms smoothCurve curveState borderDashSpec handles borderForm snapToOtherPolygons'
- instanceVariableNames: 'vertices closed filledForm arrows arrowForms smoothCurve curveState borderDashSpec handles borderForm'
classVariableNames: ''
poolDictionaries: ''
category: 'Morphic-Basic'!
!PolygonMorph commentStamp: 'md 2/24/2006 20:34' prior: 0!
This class implements a morph which can behave as four different objects depending on the the following two facts:
- is it OPEN or CLOSED?
- is it SEGMENTED or SMOOTHED.
1. The OPEN and SEGMENTED variant looks like polyline.
2. The OPEN and SMOOTHED variant looks like spline (kind of curve)
3. The CLOSED and SEGMENTED variant looks like polygon. This is actually what you get when you do
PolygonMorph new openInWorld
You get a triangle. See below how to manipulate these objects...
4. The CLOSED and SMOOTHED variant looks like blob (???)
Prototypes of this morph can also be found in "Object Catalog". Several (different variants) of this object are among "Basic" morphs.
Explore the assiciated morph-menu. It enables you
- to toggle showing of "handles". They make it possible to
- reposition already existing vertices (by moving yellow handles)
- create new vertices (by moving green handles)
- delete already existing vertices (by dragging and dropping one yellow handle closely
nearby the adjacent yellow handle
Handles can be made visible/hidden by shift+leftclicking the morph. This way it is possible
to quickly show handles, adjust vertices and then again hide handles.
- making closed polygon open, i.e. converting it to a curve (and vice versa)
- toggle smoothed/segmented line/outline
- set up custom dashing (for line, curves or borders of closed polygons
- set up custom arrow-heads (for lines resp. curves)
------------------------------------------------------------------------------------------
Implementation notes:
This class combines the old Polygon and Curve classes.
The 1-bit fillForm to make display and containment tests reasonably fast. However, this functionality is in the process of being supplanted by balloon capabilities, which should eventually provide anti-aliasing as well.
wiz 7/18/2004 21:26
s have made some changes to this class to
1) correct some bugs associated with one vertex polygons.
2) prepare for some enhancements with new curves.
3) add shaping items to menu.!
Item was changed:
----- Method: PolygonMorph>>addCustomMenuItems:hand: (in category 'menu') -----
addCustomMenuItems: aMenu 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."
super addCustomMenuItems: aMenu hand: aHandMorph.
aMenu addUpdating: #handlesShowingPhrase target: self action: #showOrHideHandles.
vertices size > 2 ifTrue:
[aMenu addUpdating: #openOrClosePhrase target: self action: #makeOpenOrClosed].
aMenu addUpdating: #smoothPhrase target: self action: #toggleSmoothing.
+ aMenu addUpdating: #snapToOtherPolygonPhrase target: self action: #toggleSnapToOtherPolygons.
aMenu addLine.
aMenu add: 'specify dashed line' translated action: #specifyDashedLine.
self isOpen ifTrue:
[aMenu addLine.
aMenu addWithLabel: '---' enablement: [self isOpen and: [arrows ~~ #none]] action: #makeNoArrows.
aMenu addWithLabel: '-->' enablement: [self isOpen and: [arrows ~~ #forward]] action: #makeForwardArrow.
aMenu addWithLabel: '<--' enablement: [self isOpen and: [arrows ~~ #back]] action: #makeBackArrow.
aMenu addWithLabel: '<->' enablement: [self isOpen and: [arrows ~~ #both]] action: #makeBothArrows.
aMenu add: 'customize arrows' translated action: #customizeArrows:.
(self hasProperty: #arrowSpec)
ifTrue: [aMenu add: 'standard arrows' translated action: #standardArrows]].!
Item was changed:
----- Method: PolygonMorph>>dropVertex:event:fromHandle: (in category 'editing') -----
+ dropVertex: ix event: evt fromHandle: handle
+ "Leave vertex in new position. If dropped ontop another vertex delete
+ this one.
- dropVertex: ix event: evt fromHandle: handle
- "Leave vertex in new position. If dropped ontop another vertex delete this one.
Check for too few vertices before deleting. The alternative
+ is not pretty -wiz"
+ | p nearestOwner |
- is not pretty -wiz"
- | p |
p := vertices at: ix.
+
+ "snap the dropped vertex to a vertex of another PolygonMorph if it is in near proximity"
+ self isSnappingToOtherPolygons
+ ifTrue: [nearestOwner := self ownerThatIsA: PasteUpMorph.
+ nearestOwner submorphs
+ do: [:each | ((each respondsTo: #vertices)
+ and: [each ~= self])
+ ifTrue: [each vertices
+ do: [:otherMorphsVertex | (otherMorphsVertex dist: p)
+ < 3
+ ifTrue: [vertices at: ix put: otherMorphsVertex]]]]].
(vertices size >= 2
and: ["check for too few vertices before deleting. The alternative
is not pretty -wiz"
((vertices atWrap: ix - 1)
dist: p)
< 3
or: [((vertices atWrap: ix + 1)
dist: p)
< 3]])
ifTrue: ["Drag a vertex onto its neighbor means delete"
+ self deleteVertexAt: ix].
- self deleteVertexAt: ix .].
evt shiftPressed
ifTrue: [self removeHandles]
ifFalse: [self addHandles
"remove then add to recreate"]!
Item was changed:
----- Method: PolygonMorph>>initialize (in category 'initialization') -----
initialize
"initialize the state of the receiver"
super initialize.
""
vertices := Array
with: 5 @ 0
with: 20 @ 10
with: 0 @ 20.
closed := true.
smoothCurve := false.
arrows := #none.
+ snapToOtherPolygons := false.
self computeBounds!
Item was added:
+ ----- Method: PolygonMorph>>isSnappingToOtherPolygons (in category 'access') -----
+ isSnappingToOtherPolygons
+ ^snapToOtherPolygons ifNil:[ snapToOtherPolygons := false].
+ !
Item was added:
+ ----- Method: PolygonMorph>>snapToOtherPolygonPhrase (in category 'menu') -----
+ snapToOtherPolygonPhrase
+ "Answer a string characterizing whether my vertices should snap to another polygons vertices."
+
+ ^ (self isSnappingToOtherPolygons ifTrue: ['<yes>'] ifFalse: ['<no>']), 'snap to other polygons' translated !
Item was added:
+ ----- Method: PolygonMorph>>toggleSnapToOtherPolygons (in category 'menu') -----
+ toggleSnapToOtherPolygons
+ ^snapToOtherPolygons := snapToOtherPolygons not!