Alexandre,
Thanks for addition of the rubberband feature. Having considered the ROExample some more, I think it would provide a better show by highlighting the available target nodes, so (to keep the application code concise) I was thinking of rearranging the API as follows... --------------- rubberband := RORubberBand new targeting: [:sourceElement | sourceElement view allElementsSelect: [:targetElement | [targetElement model first asInteger = (sourceElement model first asInteger + 1)]]]; highlightTargets; onDrop: [:rawNewEdge | rawNewEdge + ROLine. rawNewEdge to removeAllEdgesTo. rawNewEdge to view add: rawNewEdge. ROTreeLayout on: rawView elements]. --------------
where I was adding ROView>>allElementsSelect: as... -------------- allElementsSelect: aBlock | newCollection | newCollection := OrderedCollection new. self allElementsDo: [:each | (aBlock value: each) ifTrue: [newCollection add: each]]. ^newCollection --------------
However I bumped into an issue where (unless you see a more elegant solution) I feel the right thing might be to rename #allElementsDo: to #allElementsAndEdgesDo (or #alllAbstractElementsDo:) and create two new methods #allEdgesDo: and #allElementsDo:
The issue is that I was assuming I would be safe with the code "sourceElement model first" since I _know_ the model is a string, however I was surprised that this failed - due to #allElementsDo also processing edges which had no model. However trying to workaround this with the following also fails... -------------- allElementsSelect: [:targetElement | (targetElement isKindOf: ROElement) and: (targetElement model first asInteger = (sourceElement model first asInteger + 1)) ] -------------- since the right-side is not bypassed when the left-side evaluates to #true as per other languages (as well it clutters the application code)
Hence it seems useful for the (targetElement isKindOf: ROElement) to be pushed upstream. However what would such a method be called? #allElementsDo: is already taken, unless as mentioned above #allElementsDo: is renamed to #allAbstactElementsDo: and new #allEdgesDo: and #allElementsDo: are created.
Actually a new thought just occurs.... since Roassal has two major components ROEdge and ROElement, and I think it will be _very_ common to filter between them, having something like #allElementsKindOf:do: (as well as #allElementsKindOf:select:) might be useful, such that the application code would be... -------------- rubberband := RORubberBand new targeting: [:sourceElement | sourceElement view allElementsKindOf: ROElement select: [:targetElement | [targetElement model first asInteger = (sourceElement model first asInteger + 1)]]]; highlightTargets; onDrop: [:rawNewEdge | rawNewEdge + ROLine. rawNewEdge to removeAllEdgesTo. rawNewEdge to view add: rawNewEdge. ROTreeLayout on: rawView elements]. --------------
This could leave the rubberbanding mechanism flexible to later drop edges onto other edges - which might be randomly useful for something like the hyperedges discussed recently. Do you have any other ideas on achieving something similar to the last example?
cheers -ben
P.S. While it is elegant that ROAbstractElement has only one instance variable 'elements' containing both ROElements and ROEdges, it is a little unfortunate when considering the term 'elements' in general discussion and documentation that there is a semantic overlap between ROAbstactElement and ROElement that may at times be open to confusion.