diff --git a/activiti-intellij-plugin/build.gradle b/activiti-intellij-plugin/build.gradle index 742687344..d9bf5ed34 100644 --- a/activiti-intellij-plugin/build.gradle +++ b/activiti-intellij-plugin/build.gradle @@ -42,6 +42,10 @@ intellij { plugins = intellijPlatformPlugins } +runIde { + jbrVersion = runIdeJbrVersion +} + publishPlugin { token = intellijPublishToken } @@ -82,4 +86,4 @@ jacocoTestReport { xml.enabled true csv.enabled false } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/DefaultBpmnProcessRenderer.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/DefaultBpmnProcessRenderer.kt index 7d9905e17..6441c9c7f 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/DefaultBpmnProcessRenderer.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/DefaultBpmnProcessRenderer.kt @@ -167,7 +167,7 @@ class DefaultBpmnProcessRenderer(private val project: Project, val icons: IconPr } private fun createRootProcessElem(state: () -> RenderState, elements: MutableList, elementsById: MutableMap): BaseBpmnRenderElement { - val processElem = PlaneRenderElement(state().currentState.processDiagramId(), state().currentState.processId, state, mutableListOf()) + val processElem = PlaneRenderElement(state().currentState.processDiagramId(), state().currentState.processId, state) elements += processElem elementsById[state().currentState.processId] = processElem return processElem @@ -197,7 +197,7 @@ class DefaultBpmnProcessRenderer(private val project: Project, val icons: IconPr elementsById.forEach { (id, renderElem) -> val elem = state().currentState.elementByBpmnId[id] elem?.parent?.let {elementsById[it]}?.let { if (it is BaseBpmnRenderElement) it else null }?.let { parent -> - parent.children.add(renderElem) + parent.addInnerElement(renderElem) parent.let { renderElem.parents.add(it) } } } @@ -243,8 +243,8 @@ class DefaultBpmnProcessRenderer(private val project: Project, val icons: IconPr is BpmnSubProcess -> NoIconShape(id, bpmn.id, shape, state, Colors.PROCESS_COLOR, Colors.ELEMENT_BORDER_COLOR, Colors.SUBPROCESS_TEXT_COLOR, areaType = AreaType.SHAPE_THAT_NESTS) is BpmnEventSubprocess -> NoIconShape(id, bpmn.id, shape, state, Colors.PROCESS_COLOR, Colors.ELEMENT_BORDER_COLOR, Colors.SUBPROCESS_TEXT_COLOR, areaType = AreaType.SHAPE_THAT_NESTS, borderStroke = DASHED_STROKE) is BpmnTransactionalSubProcess -> NoIconDoubleBorderShape(id, bpmn.id, shape, state, areaType = AreaType.SHAPE_THAT_NESTS) - is BpmnCollapsedSubprocess -> ExpandableShapeNoIcon(id, bpmn.id, isCollapsed(bpmn.id, state), icons.plus, icons.minus, shape, state, areaType = AreaType.SHAPE_THAT_NESTS) - is BpmnTransactionCollapsedSubprocess -> ExpandableShapeNoIcon(id, bpmn.id, isCollapsed(bpmn.id, state), icons.plus, icons.minus, shape, state, areaType = AreaType.SHAPE_THAT_NESTS) + is BpmnCollapsedSubprocess -> ExpandableShapeNoIcon(id, bpmn.id, icons.plus, icons.minus, shape, state, areaType = AreaType.SHAPE_THAT_NESTS) + is BpmnTransactionCollapsedSubprocess -> ExpandableShapeNoIcon(id, bpmn.id, icons.plus, icons.minus, shape, state, areaType = AreaType.SHAPE_THAT_NESTS) is BpmnCallActivity -> NoIconShape(id, bpmn.id, shape, state) is BpmnAdHocSubProcess -> BottomMiddleIconShape(id, bpmn.id, icons.tilde, shape, state, areaType = AreaType.SHAPE_THAT_NESTS) is BpmnExclusiveGateway -> IconShape(id, bpmn.id, icons.exclusiveGateway, shape, state) @@ -269,10 +269,6 @@ class DefaultBpmnProcessRenderer(private val project: Project, val icons: IconPr } } - private fun isCollapsed(id: BpmnElementId, state: () -> RenderState): Boolean { - return !(state().currentState.elemUiOnlyPropertiesByStaticElementId[id]?.get(UiOnlyPropertyType.EXPANDED)?.value as Boolean? ?: false) - } - private fun drawSelectionRect(state: RenderContext) { state.interactionContext.dragSelectionRect?.let { val rect = it.toRect() @@ -412,4 +408,4 @@ data class TreeState ( internal val version: Long, ) { internal lateinit var domRoot: BaseBpmnRenderElement -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/RenderContext.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/RenderContext.kt index bd9d49d3d..76cde1924 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/RenderContext.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/RenderContext.kt @@ -9,10 +9,15 @@ import com.valb3r.bpmn.intellij.plugin.core.render.elements.RenderState import com.valb3r.bpmn.intellij.plugin.core.state.CurrentStateProvider data class RenderContext( - val project: Project, - val canvas: CanvasPainter, - val selectedIds: Set, - val interactionContext: ElementInteractionContext, - val stateProvider: CurrentStateProvider, - var cachedDom: TreeState? = null -) \ No newline at end of file + val project: Project, + val canvas: CanvasPainter, + val selectedIds: Set, + val interactionContext: ElementInteractionContext, + val stateProvider: CurrentStateProvider, + var cachedDom: TreeState? = null +) { + // Just a FIXME for Kotlin debugger not to get to OutOfMemory + override fun toString(): String { + return "" + } +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/BaseDiagramRenderElement.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/BaseDiagramRenderElement.kt index 1ef61ebcb..462878b80 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/BaseDiagramRenderElement.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/BaseDiagramRenderElement.kt @@ -31,7 +31,8 @@ abstract class BaseDiagramRenderElement( var isVisible: Boolean? = null abstract val areaType: AreaType - open val children: MutableList = mutableListOf() + protected val innerElements: MutableList = mutableListOf() + open val children: List = innerElements /** * Parents in the order: direct parent, parent of direct parent... @@ -39,6 +40,11 @@ abstract class BaseDiagramRenderElement( */ open val parents: MutableList = mutableListOf() + /** + * View transformation level for this element (will limit scoped view transformation to this level) + */ + open var viewTransformLevel: DiagramElementId? = null + open fun multipleElementsSelected(): Boolean { return state().ctx.selectedIds.size > 1 } @@ -121,6 +127,13 @@ abstract class BaseDiagramRenderElement( return result } + open fun addInnerElement(elem: BaseDiagramRenderElement) { + elem.viewTransformLevel = this.viewTransformLevel + innerElements.add(elem) + } + + abstract fun currentRect(): Rectangle2D.Float + protected open fun rootAndEnumerateChildrenRecursively(root: BaseDiagramRenderElement) : List { val result = mutableListOf() result += root @@ -219,8 +232,7 @@ abstract class BaseDiagramRenderElement( abstract fun doResizeWithoutChildren(dw: Float, dh: Float) abstract fun doResizeEndWithoutChildren(dw: Float, dh: Float): MutableList - protected abstract fun currentRect(): Rectangle2D.Float - protected abstract fun currentOnScreenRect(camera: Camera): Rectangle2D.Float + abstract fun currentOnScreenRect(camera: Camera): Rectangle2D.Float protected abstract fun waypointAnchors(camera: Camera): MutableSet protected abstract fun shapeAnchors(camera: Camera): MutableSet @@ -246,17 +258,18 @@ abstract class BaseDiagramRenderElement( val batch = findExpansionViewTransformationsToCompensate() val trackingPoint = Point2D.Float(rect.x, rect.y) - val viewTransformedPoint = batch.transform(elementId, trackingPoint) + val transform = PointTransformationIntrospection(applyTransformationAt = viewTransformLevel) + val viewTransformedPoint = batch.transform(elementId, trackingPoint, transform) val currentPoint = Point2D.Float(viewTransformedPoint.x + dx, viewTransformedPoint.y + dy) - val inverted = ViewTransformInverter().invert(elementId, currentPoint, trackingPoint, batch) + val inverted = ViewTransformInverter().invert(elementId, currentPoint, trackingPoint, batch, transform) return Point2D.Float(inverted.x - rect.x, inverted.y - rect.y) } - protected fun compensateExpansionViewOnLocation(targetElement: DiagramElementId, location: Point2D.Float, initialGuess: Point2D.Float): Point2D.Float { + protected fun compensateExpansionViewOnLocation(elementToCompensate: DiagramElementId, location: Point2D.Float, initialGuess: Point2D.Float, target: DiagramElementId?): Point2D.Float { val batch = findExpansionViewTransformationsToCompensate() - val inverted = ViewTransformInverter().invert(targetElement, location, initialGuess, batch) + val inverted = ViewTransformInverter().invert(elementToCompensate, location, initialGuess, batch, PointTransformationIntrospection(target, applyTransformationAt = this.viewTransformLevel)) return Point2D.Float(inverted.x, inverted.y) } @@ -283,4 +296,4 @@ abstract class BaseDiagramRenderElement( currentOnScreenRect(state().ctx.canvas.camera) children.forEach {it.currentOnScreenRect(state().ctx.canvas.camera)} } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/AnchorElement.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/AnchorElement.kt index 480bec466..456589f81 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/AnchorElement.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/AnchorElement.kt @@ -16,7 +16,7 @@ import java.awt.geom.Rectangle2D abstract class AnchorElement( elementId: DiagramElementId, - private val attachedTo: DiagramElementId?, + protected val attachedTo: DiagramElementId?, protected val currentLocation: Point2D.Float, state: () -> RenderState ): BaseDiagramRenderElement(elementId, state) { @@ -25,7 +25,7 @@ abstract class AnchorElement( get() = currentLocation val transformedLocation: Point2D.Float - get() = state().viewTransform(elementId).transform(elementId, currentLocation, PointTransformationIntrospection(attachedTo)) + get() = state().viewTransform(elementId).transform(elementId, currentLocation, PointTransformationIntrospection(attachedTo, viewTransformLevel)) override fun drawActionsRight(x: Float, y: Float): Map { // NOP @@ -68,4 +68,4 @@ abstract class AnchorElement( override fun getEventsToDeleteElement(): List { return listOf() } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/CircleAnchorElement.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/CircleAnchorElement.kt index 477fea0d0..263e2ad92 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/CircleAnchorElement.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/CircleAnchorElement.kt @@ -21,7 +21,7 @@ abstract class CircleAnchorElement( elementId: DiagramElementId, attachedTo: DiagramElementId?, currentLocation: Point2D.Float, - private val radius: Float, + protected val radius: Float, private val bodyColor: Colors, state: () -> RenderState ) : AnchorElement(elementId, attachedTo, currentLocation, state) { @@ -39,7 +39,9 @@ abstract class CircleAnchorElement( 2.0f * radius, 2.0f * radius ), - AreaType.POINT + AreaType.POINT, + viewTransformLevel, + attachedTo = attachedTo ) ) } @@ -95,4 +97,4 @@ abstract class CircleAnchorElement( protected open fun isRenderable(): Boolean { return true } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/EdgeExtractionAnchor.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/EdgeExtractionAnchor.kt index b50d64651..705452d00 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/EdgeExtractionAnchor.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/EdgeExtractionAnchor.kt @@ -39,7 +39,8 @@ class EdgeExtractionAnchor( imageHeight ), AreaType.POINT, - parent + viewTransformLevel, + attachedTo = parent ) ) } @@ -78,4 +79,4 @@ class EdgeExtractionAnchor( override fun waypointAnchors(camera: Camera): MutableSet { return mutableSetOf(Anchor(transformedLocation)) } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/ShapeResizeAnchorBottom.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/ShapeResizeAnchorBottom.kt index 8703e5e47..b628b560b 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/ShapeResizeAnchorBottom.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/ShapeResizeAnchorBottom.kt @@ -31,7 +31,8 @@ class ShapeResizeAnchorBottom( icon.iconHeight.toFloat() ), AreaType.SHAPE, - parent + viewTransformLevel, + attachedTo = parent ) ) } @@ -62,4 +63,4 @@ class ShapeResizeAnchorBottom( override fun zIndex(): Int { return ICON_Z_INDEX } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/ShapeResizeAnchorTop.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/ShapeResizeAnchorTop.kt index ad2ce6833..da0ecbb38 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/ShapeResizeAnchorTop.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/ShapeResizeAnchorTop.kt @@ -36,7 +36,8 @@ class ShapeResizeAnchorTop( height ), AreaType.SHAPE, - parent + viewTransformLevel, + attachedTo = parent ) ) } @@ -67,4 +68,4 @@ class ShapeResizeAnchorTop( override fun zIndex(): Int { return ICON_Z_INDEX } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/VirtualWaypoint.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/VirtualWaypoint.kt index 97a5b9b16..991645aea 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/VirtualWaypoint.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/anchors/VirtualWaypoint.kt @@ -49,4 +49,4 @@ class VirtualWaypoint( override fun waypointAnchors(camera: Camera): MutableSet { return if (isActiveOrDragged()) return super.waypointAnchors(camera) else mutableSetOf() } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/buttons/ButtonWithAnchor.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/buttons/ButtonWithAnchor.kt index 58ae16af6..c454b3f70 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/buttons/ButtonWithAnchor.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/buttons/ButtonWithAnchor.kt @@ -41,7 +41,8 @@ class ButtonWithAnchor( imageWidth, imageHeight ), - AreaType.POINT + AreaType.POINT, + viewTransformLevel ) ) } @@ -73,4 +74,4 @@ class ButtonWithAnchor( override fun waypointAnchors(camera: Camera): MutableSet { return mutableSetOf(Anchor(transformedLocation)) } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/edges/BaseEdgeRenderElement.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/edges/BaseEdgeRenderElement.kt index 8497c381e..7be24d580 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/edges/BaseEdgeRenderElement.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/edges/BaseEdgeRenderElement.kt @@ -17,6 +17,8 @@ import com.valb3r.bpmn.intellij.plugin.core.render.elements.RenderState import com.valb3r.bpmn.intellij.plugin.core.render.elements.anchors.AnchorElement import com.valb3r.bpmn.intellij.plugin.core.render.elements.anchors.PhysicalWaypoint import com.valb3r.bpmn.intellij.plugin.core.render.elements.anchors.VirtualWaypoint +import com.valb3r.bpmn.intellij.plugin.core.render.elements.viewtransform.PointTransformationIntrospection +import com.valb3r.bpmn.intellij.plugin.core.render.elements.viewtransform.RectangleTransformationIntrospection import java.awt.Color import java.awt.geom.Area import java.awt.geom.Point2D @@ -32,7 +34,15 @@ abstract class BaseEdgeRenderElement( private val anchors = computeAnchors() - override val children: MutableList = anchors as MutableList + override var viewTransformLevel: DiagramElementId? = null + get() = super.viewTransformLevel + set(value) { + super.viewTransformLevel = value + field = value + anchors.forEach { it.viewTransformLevel = value} + } + + override val children: List = anchors as MutableList + innerElements val edgeElem: EdgeWithIdentifiableWaypoints get() = edge @@ -90,17 +100,17 @@ abstract class BaseEdgeRenderElement( } override fun currentOnScreenRect(camera: Camera): Rectangle2D.Float { - val minX = edge.waypoint.minBy { it.x }?.x ?: 0.0f - val minY = edge.waypoint.minBy { it.y }?.y ?: 0.0f - val maxX = edge.waypoint.maxBy { it.x }?.x ?: 0.0f - val maxY = edge.waypoint.maxBy { it.y }?.y ?: 0.0f + val elems = anchors.filterIsInstance().map { it.transformedLocation } + val stX = elems.minBy { it.x }?.x ?: 0.0f + val stY = elems.minBy { it.y }?.y ?: 0.0f + val enX = elems.maxBy { it.x }?.x ?: 0.0f + val enY = elems.maxBy { it.y }?.y ?: 0.0f - // Edge itself can't be translated, so no viewTransform return Rectangle2D.Float( - minX, - minY, - maxX - minX, - maxY - minY + stX, + stY, + enX - stX, + enY - stY ) } @@ -150,12 +160,14 @@ abstract class BaseEdgeRenderElement( val numPhysicals = edge.waypoint.filter { it.physical }.size var physicalPos = -1 return edge.waypoint.map { - if (it.physical) { + val result = if (it.physical) { physicalPos++ PhysicalWaypoint(it.id, findAttachedToElement(physicalPos, numPhysicals), edge.id, edge.bpmnElement, edge, physicalPos, numPhysicals, Point2D.Float(it.x, it.y), state).let { it.parents.add(this); it } } else { VirtualWaypoint(it.id, edge.id, edge, Point2D.Float(it.x, it.y), state).let { it.parents.add(this); it } } + result.viewTransformLevel = viewTransformLevel + return@map result }.toMutableList() } @@ -172,4 +184,4 @@ abstract class BaseEdgeRenderElement( else -> null } } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/planes/PlaneRenderElement.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/planes/PlaneRenderElement.kt index 653cc6072..a0e85bc59 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/planes/PlaneRenderElement.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/planes/PlaneRenderElement.kt @@ -19,8 +19,7 @@ import java.awt.geom.Rectangle2D class PlaneRenderElement( elementId: DiagramElementId, bpmnElementId: BpmnElementId, - state: () -> RenderState, - override val children: MutableList = mutableListOf() + state: () -> RenderState ): BaseBpmnRenderElement(elementId, bpmnElementId, state) { override val areaType: AreaType @@ -70,6 +69,11 @@ class PlaneRenderElement( override fun drawActionsRight(x: Float, y: Float): Map { return mutableMapOf() } + + override fun addInnerElement(elem: BaseDiagramRenderElement) { + elem.viewTransformLevel = this.elementId + innerElements.add(elem) + } } private class InfiniteShape: Area() { @@ -105,4 +109,4 @@ private class InfiniteShape: Area() { override fun getBounds(): Rectangle { return Rectangle() } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/AnyShapeNestableIconShape.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/AnyShapeNestableIconShape.kt index 43fe9352e..73af01e9c 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/AnyShapeNestableIconShape.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/AnyShapeNestableIconShape.kt @@ -12,6 +12,7 @@ import com.valb3r.bpmn.intellij.plugin.core.render.AreaWithZindex import com.valb3r.bpmn.intellij.plugin.core.render.Camera import com.valb3r.bpmn.intellij.plugin.core.render.elements.Anchor import com.valb3r.bpmn.intellij.plugin.core.render.elements.BaseBpmnRenderElement +import com.valb3r.bpmn.intellij.plugin.core.render.elements.BaseDiagramRenderElement import com.valb3r.bpmn.intellij.plugin.core.render.elements.RenderState import com.valb3r.bpmn.intellij.plugin.core.render.elements.internal.CascadeTranslationOrChangesToWaypoint import java.awt.geom.Point2D @@ -27,6 +28,11 @@ class AnyShapeNestableIconShape( override val areaType: AreaType get() = AreaType.SELECTS_DRAG_TARGET + override fun addInnerElement(elem: BaseDiagramRenderElement) { + elem.viewTransformLevel = this.elementId + innerElements.add(elem) + } + fun handleParentNestingChange(droppedOn: BpmnElementId): MutableList { val newEvents = mutableListOf() val currentParent = parents.firstOrNull() @@ -103,4 +109,4 @@ class AnyShapeNestableIconShape( return parents.first().parents.first() } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/ExpandableShapeNoIcon.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/ExpandableShapeNoIcon.kt index c5efb872d..49d5a3f51 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/ExpandableShapeNoIcon.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/ExpandableShapeNoIcon.kt @@ -8,18 +8,21 @@ import com.valb3r.bpmn.intellij.plugin.core.events.BooleanUiOnlyValueUpdatedEven import com.valb3r.bpmn.intellij.plugin.core.properties.uionly.UiOnlyPropertyType import com.valb3r.bpmn.intellij.plugin.core.render.AreaType import com.valb3r.bpmn.intellij.plugin.core.render.AreaWithZindex +import com.valb3r.bpmn.intellij.plugin.core.render.Camera import com.valb3r.bpmn.intellij.plugin.core.render.RenderContext +import com.valb3r.bpmn.intellij.plugin.core.render.elements.Anchor import com.valb3r.bpmn.intellij.plugin.core.render.elements.BaseDiagramRenderElement import com.valb3r.bpmn.intellij.plugin.core.render.elements.RenderState import com.valb3r.bpmn.intellij.plugin.core.render.elements.buttons.ButtonWithAnchor +import com.valb3r.bpmn.intellij.plugin.core.render.elements.viewtransform.DragViewTransform import com.valb3r.bpmn.intellij.plugin.core.render.elements.viewtransform.ExpandViewTransform +import com.valb3r.bpmn.intellij.plugin.core.render.elements.viewtransform.PreTransformHandler import java.awt.geom.Point2D import javax.swing.Icon class ExpandableShapeNoIcon( elementId: DiagramElementId, bpmnElementId: BpmnElementId, - private val collapsed: Boolean, plusIcon: Icon, minusIcon: Icon, shape: ShapeElement, @@ -30,21 +33,28 @@ class ExpandableShapeNoIcon( override val areaType: AreaType = AreaType.SHAPE ) : ResizeableShapeRenderElement(elementId, bpmnElementId, shape, state) { + override fun addInnerElement(elem: BaseDiagramRenderElement) { + elem.viewTransformLevel = this.elementId + innerElements.add(elem) + state().viewTransforms[elem.elementId] = DragViewTransform( + shape.bounds().first.x, + shape.bounds().first.y, + PreTransformHandler(mutableListOf(state().viewTransform(elem.elementId))) + ) + } + private val expandButton = ButtonWithAnchor( DiagramElementId("EXPAND:" + shape.id.id), Point2D.Float((shape.bounds().first.x + shape.bounds().second.x) / 2.0f, shape.bounds().second.y), - if (collapsed) plusIcon else minusIcon, - { mutableListOf(BooleanUiOnlyValueUpdatedEvent(bpmnElementId, UiOnlyPropertyType.EXPANDED, !collapsed)) }, + if (isCollapsed()) plusIcon else minusIcon, + { mutableListOf(BooleanUiOnlyValueUpdatedEvent(bpmnElementId, UiOnlyPropertyType.EXPANDED, isCollapsed())) }, state ) - override val children: MutableList = ( - super.children + expandButton - - ).toMutableList() + override val children: List + get() = ((if (!isCollapsed()) innerElements else mutableListOf()) + actions + expandButton) override fun doRender(ctx: RenderContext, shapeCtx: ShapeCtx): Map { - val area = ctx.canvas.drawRoundedRect( shapeCtx.shape, shapeCtx.name, @@ -57,19 +67,44 @@ class ExpandableShapeNoIcon( } override fun createIfNeededExpandViewTransform() { - if (this.collapsed) { + if (isCollapsed()) { return } state().baseTransform.addPreTransform(ExpandViewTransform( elementId, + viewTransformLevel!!, shape.rectBounds(), shape.rectBounds().centerX.toFloat(), shape.rectBounds().centerY.toFloat(), 100.0f, 100.0f, - enumerateChildrenRecursively().map { it.elementId }.toSet() )) super.createIfNeededExpandViewTransform() } -} \ No newline at end of file + + // Simplifying anchor model as inversion of view transform of intermediate anchors is not stable + override fun waypointAnchors(camera: Camera): MutableSet { + val rect = currentOnScreenRect(camera) + val halfWidth = rect.width / 2.0f + val halfHeight = rect.height / 2.0f + + val cx = rect.x + rect.width / 2.0f + val cy = rect.y + rect.height / 2.0f + return mutableSetOf( + Anchor(Point2D.Float(cx - halfWidth, cy), 10), + Anchor(Point2D.Float(cx + halfWidth, cy), 10), + Anchor(Point2D.Float(cx, cy - halfHeight), 10), + Anchor(Point2D.Float(cx, cy + halfHeight), 10), + ) + } + + // Central anchor does not make sense for this kind of shape + override fun shapeAnchors(camera: Camera): MutableSet { + return mutableSetOf() + } + + private fun isCollapsed(): Boolean { + return !(state().currentState.elemUiOnlyPropertiesByStaticElementId[bpmnElementId]?.get(UiOnlyPropertyType.EXPANDED)?.value as Boolean? ?: false) + } +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/ResizeableShapeRenderElement.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/ResizeableShapeRenderElement.kt index 3efff1836..0a35391ed 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/ResizeableShapeRenderElement.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/ResizeableShapeRenderElement.kt @@ -31,11 +31,17 @@ abstract class ResizeableShapeRenderElement( ShapeResizeAnchorBottom(DiagramElementId("BOTTOM:" + shape.id.id), elementId, Point2D.Float(shape.bounds().second.x, shape.bounds().second.y), { doComputeLocationChangesBasedOnTransformationWithCascade() }, state) ) - override val children: MutableList = mutableListOf( - anchors.first, - anchors.second, - edgeExtractionAnchor - ) + protected val actions = mutableListOf(anchors.first, anchors.second, edgeExtractionAnchor) + + override var viewTransformLevel: DiagramElementId? + get() = super.viewTransformLevel + set(value) { + super.viewTransformLevel = value + actions.forEach { it.viewTransformLevel = viewTransformLevel } + } + + override val children: List + get() = actions + innerElements override fun drawActionsRight(x: Float, y: Float): Map { val spaceCoeff = 1.5f @@ -131,4 +137,4 @@ abstract class ResizeableShapeRenderElement( } } } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/ShapeRenderElement.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/ShapeRenderElement.kt index e46309097..8145bf3fc 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/ShapeRenderElement.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/shapes/ShapeRenderElement.kt @@ -4,10 +4,7 @@ import com.valb3r.bpmn.intellij.plugin.bpmn.api.bpmn.BpmnElementId import com.valb3r.bpmn.intellij.plugin.bpmn.api.bpmn.elements.BpmnSequenceFlow import com.valb3r.bpmn.intellij.plugin.bpmn.api.bpmn.elements.WithParentId import com.valb3r.bpmn.intellij.plugin.bpmn.api.diagram.DiagramElementId -import com.valb3r.bpmn.intellij.plugin.bpmn.api.diagram.elements.BoundsElement -import com.valb3r.bpmn.intellij.plugin.bpmn.api.diagram.elements.EdgeElement -import com.valb3r.bpmn.intellij.plugin.bpmn.api.diagram.elements.ShapeElement -import com.valb3r.bpmn.intellij.plugin.bpmn.api.diagram.elements.WaypointElement +import com.valb3r.bpmn.intellij.plugin.bpmn.api.diagram.elements.* import com.valb3r.bpmn.intellij.plugin.bpmn.api.events.Event import com.valb3r.bpmn.intellij.plugin.bpmn.api.events.LocationUpdateWithId import com.valb3r.bpmn.intellij.plugin.bpmn.api.info.Property @@ -22,6 +19,7 @@ import com.valb3r.bpmn.intellij.plugin.core.render.* import com.valb3r.bpmn.intellij.plugin.core.render.elements.* import com.valb3r.bpmn.intellij.plugin.core.render.elements.anchors.EdgeExtractionAnchor import com.valb3r.bpmn.intellij.plugin.core.render.elements.internal.CascadeTranslationOrChangesToWaypoint +import com.valb3r.bpmn.intellij.plugin.core.render.elements.planes.PlaneRenderElement import com.valb3r.bpmn.intellij.plugin.core.render.elements.viewtransform.NullViewTransform import com.valb3r.bpmn.intellij.plugin.core.render.elements.viewtransform.RectangleTransformationIntrospection import com.valb3r.bpmn.intellij.plugin.core.state.CurrentState @@ -46,11 +44,19 @@ abstract class ShapeRenderElement( cascadeTo = computeCascadables() } - override val children: MutableList = mutableListOf(edgeExtractionAnchor) + override val children: List = mutableListOf(edgeExtractionAnchor) + innerElements val shapeElem: ShapeElement get() = shape + override var viewTransformLevel: DiagramElementId? = null + get() = super.viewTransformLevel + set(value) { + super.viewTransformLevel = value + field = value + edgeExtractionAnchor.viewTransformLevel = viewTransformLevel + } + override fun doRenderWithoutChildren(ctx: RenderContext): Map { val elem = state().currentState.elementByDiagramId[shape.id] val props = state().currentState.elemPropertiesByStaticElementId[elem] @@ -182,7 +188,7 @@ abstract class ShapeRenderElement( } override fun currentOnScreenRect(camera: Camera): Rectangle2D.Float { - return state().viewTransform(elementId).transform(elementId, RectangleTransformationIntrospection(shape.rectBounds(), AreaType.SHAPE)) + return state().viewTransform(elementId).transform(elementId, RectangleTransformationIntrospection(shape.rectBounds(), AreaType.SHAPE, viewTransformLevel)) } override fun currentRect(): Rectangle2D.Float { @@ -275,7 +281,7 @@ abstract class ShapeRenderElement( } private fun computeAnchorLocation(currentElementId: DiagramElementId, state: () -> RenderState): EdgeExtractionAnchor { - return EdgeExtractionAnchor( + val anchor = EdgeExtractionAnchor( DiagramElementId("NEW-SEQUENCE:" + shape.id.id), currentElementId, actionsAnchorTopEnd(Rectangle2D.Float( @@ -287,6 +293,8 @@ abstract class ShapeRenderElement( { droppedOn, allDroppedOn -> onWaypointAnchorDragEnd(droppedOn, allDroppedOn) }, state ) + anchor.parents += this + return anchor } private fun onWaypointAnchorDragEnd(droppedOn: BpmnElementId?, allDroppedOnAreas: Map): MutableList { @@ -296,13 +304,14 @@ abstract class ShapeRenderElement( } val sourceElem = state().currentState.elementByBpmnId[bpmnElementId] ?: return mutableListOf() + val targetElem = state().currentState.diagramByElementId[droppedOn]?.let { state().elemMap[it] } val newSequenceBpmn = newElementsFactory(state().ctx.project).newOutgoingSequence(sourceElem.element) val anchors = findSequenceAnchors(targetArea) ?: return mutableListOf() val notYetExistingDiagramId = DiagramElementId("") val sourceBounds = shape.rectBounds() - val firstAnchorCompensated = compensateExpansionViewOnLocation(notYetExistingDiagramId, anchors.first, Point2D.Float(sourceBounds.centerX.toFloat(), sourceBounds.centerY.toFloat())) - val secondAnchorCompensated = compensateExpansionViewOnLocation(notYetExistingDiagramId, anchors.second, anchors.second) + val firstAnchorCompensated = compensateExpansionViewOnLocation(notYetExistingDiagramId, anchors.first, Point2D.Float(sourceBounds.centerX.toFloat(), sourceBounds.centerY.toFloat()), elementId) + val secondAnchorCompensated = compensateExpansionViewOnLocation(notYetExistingDiagramId, anchors.second, initialGuess(targetElem, anchors.second), targetElem?.elementId) val newSequenceDiagram = newElementsFactory(state().ctx.project).newDiagramObject(EdgeElement::class, newSequenceBpmn) .copy(waypoint = listOf( WaypointElement(firstAnchorCompensated.x, firstAnchorCompensated.y), @@ -323,6 +332,14 @@ abstract class ShapeRenderElement( ) } + private fun initialGuess(targetElem: BaseDiagramRenderElement?, pos: Point2D.Float): Point2D.Float { + if (targetElem is PlaneRenderElement || null == targetElem) { + return pos + } + + return Point2D.Float(targetElem.currentRect().centerX.toFloat(), targetElem.currentRect().centerY.toFloat()) + } + private fun findSequenceAnchors(droppedOnTarget: AreaWithZindex): Pair? { val allStartWaypointsAnchors = waypointAnchors(state().ctx.canvas.camera) val allEndWaypointsAnchors = droppedOnTarget.anchorsForWaypoints @@ -390,4 +407,4 @@ abstract class ShapeRenderElement( fun cartesianProduct(first: Collection, second: Collection): Sequence> { return first.asSequence().flatMap { lhsElem -> second.asSequence().map { rhsElem -> lhsElem to rhsElem } } } -} \ No newline at end of file +} diff --git a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/viewtransform/ViewTransform.kt b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/viewtransform/ViewTransform.kt index efe4e8f29..36ac77c4b 100644 --- a/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/viewtransform/ViewTransform.kt +++ b/bpmn-intellij-plugin-core/src/main/kotlin/com/valb3r/bpmn/intellij/plugin/core/render/elements/viewtransform/ViewTransform.kt @@ -5,11 +5,13 @@ import com.valb3r.bpmn.intellij.plugin.core.render.AreaType import com.valb3r.bpmn.intellij.plugin.core.render.elements.EPSILON import java.awt.geom.Point2D import java.awt.geom.Rectangle2D +import java.lang.Math.pow import kotlin.math.abs +import kotlin.math.pow import kotlin.random.Random.Default.nextFloat -data class RectangleTransformationIntrospection(val rect: Rectangle2D.Float, val type: AreaType, val attachedTo: DiagramElementId? = null) -data class PointTransformationIntrospection(val attachedTo: DiagramElementId? = null) +data class RectangleTransformationIntrospection(val rect: Rectangle2D.Float, val type: AreaType, val applyTransformationAt: DiagramElementId? = null, val attachedTo: DiagramElementId? = null) +data class PointTransformationIntrospection(val attachedTo: DiagramElementId? = null, val applyTransformationAt: DiagramElementId? = null, val selectCloseQuirkWithin: Float? = null) interface PreTransformable { fun preTransform(elementId: DiagramElementId, rectTransformationIntrospection: RectangleTransformationIntrospection): Rectangle2D.Float @@ -68,7 +70,9 @@ class NullViewTransform(private val preTransform: PreTransformHandler = PreTrans } data class DragViewTransform( - val dx: Float, val dy: Float, private val preTransform: PreTransformHandler = PreTransformHandler() + private val dx: Float, + private val dy: Float, + private val preTransform: PreTransformHandler = PreTransformHandler() ): ViewTransform, PreTransformable by preTransform { override fun transform(elementId: DiagramElementId, rectTransformationIntrospection: RectangleTransformationIntrospection): Rectangle2D.Float { @@ -115,12 +119,12 @@ data class ResizeViewTransform( class ExpandViewTransform( private val expandedElementId: DiagramElementId, + private val expandOnElementLevel: DiagramElementId, private val shape: Rectangle2D.Float, private val cx: Float, private val cy: Float, private val dx: Float, private val dy: Float, - private val excludeIds: Set, private val preTransform: PreTransformHandler = PreTransformHandler() ): ViewTransform, PreTransformable by preTransform { @@ -130,7 +134,7 @@ class ExpandViewTransform( override fun transform(elementId: DiagramElementId, rectTransformationIntrospection: RectangleTransformationIntrospection): Rectangle2D.Float { val rect = rectTransformationIntrospection.rect val transformed = preTransform(elementId, rectTransformationIntrospection) - if (excludeIds.contains(elementId)) { + if (expandOnElementLevel != rectTransformationIntrospection.applyTransformationAt) { fillRectangleQuirk(elementId, rect, Point2D.Float()) return transformed } @@ -140,11 +144,9 @@ class ExpandViewTransform( val center = transformPoint(Point2D.Float(transformed.x + halfWidth, transformed.y + halfHeight)) - if (rectTransformationIntrospection.type == AreaType.POINT) { - val quirkFound = quirkForRectangles[rectTransformationIntrospection.attachedTo] - if (null != quirkFound) { - return Rectangle2D.Float(transformed.x + quirkFound.displacement.x, transformed.y + quirkFound.displacement.y, rect.width, rect.height) - } + val managedTransform = transformManagedByParent(transformed, rect, rectTransformationIntrospection) + if (null != managedTransform) { + return managedTransform } if (elementId == expandedElementId) { @@ -157,31 +159,13 @@ class ExpandViewTransform( return Rectangle2D.Float(center.x - halfWidth, center.y - halfHeight, rect.width, rect.height) } - private fun fillRectangleQuirkIfNeeded(rectTransformationIntrospection: RectangleTransformationIntrospection, elementId: DiagramElementId, rect: Rectangle2D.Float, center: Point2D.Float, transformed: Rectangle2D.Float, halfWidth: Float, halfHeight: Float) { - if (rectTransformationIntrospection.type.nests || rectTransformationIntrospection.type == AreaType.SHAPE) { - fillRectangleQuirk(elementId, rect, Point2D.Float(center.x - transformed.x - halfWidth, center.y - transformed.y - halfHeight)) - } - } - - private fun fillRectangleQuirk(elementId: DiagramElementId, rect: Rectangle2D.Float, delta: Point2D.Float) { - quirkForRectangles[elementId] = RectangleQuirk( - Rectangle2D.Float( - rect.x - quirkEpsilon, - rect.y - quirkEpsilon, - rect.width + quirkEpsilon, - rect.height + quirkEpsilon - ), - delta - ) - } - override fun transform(elementId: DiagramElementId, point: Point2D.Float): Point2D.Float { return transform(elementId, point, PointTransformationIntrospection()) } override fun transform(elementId: DiagramElementId, point: Point2D.Float, introspection: PointTransformationIntrospection): Point2D.Float { val transformed = preTransform(elementId, point, introspection) - if (excludeIds.contains(elementId)) { + if (expandOnElementLevel != introspection.applyTransformationAt) { return transformed } @@ -189,7 +173,15 @@ class ExpandViewTransform( return transformPoint(transformed) } - val quirkFound = quirkForRectangles[introspection.attachedTo] + var quirkFound = quirkForRectangles[introspection.attachedTo] + if (null == quirkFound && null != introspection.selectCloseQuirkWithin) { + fun quirkDistance(it: RectangleQuirk) = (point.x - it.originalRectangle2D.x).pow(2) + (point.y - it.originalRectangle2D.y).pow(2) + val bestQuirk = quirkForRectangles.values.minBy { quirkDistance(it) } + if (null != bestQuirk && (quirkDistance(bestQuirk) < introspection.selectCloseQuirkWithin)) { + quirkFound = bestQuirk + } + } + if (null != quirkFound) { return Point2D.Float(transformed.x + quirkFound.displacement.x, transformed.y + quirkFound.displacement.y) } @@ -197,12 +189,40 @@ class ExpandViewTransform( return transformPoint(transformed) } + private fun transformManagedByParent(transformed: Rectangle2D.Float, rect: Rectangle2D.Float, rectTransformationIntrospection: RectangleTransformationIntrospection): Rectangle2D.Float? { + val quirkFound: RectangleQuirk? = quirkForRectangles[rectTransformationIntrospection.attachedTo] + + return if (null != quirkFound) { + Rectangle2D.Float(transformed.x + quirkFound.displacement.x, transformed.y + quirkFound.displacement.y, rect.width, rect.height) + } else { + null + } + } + + private fun fillRectangleQuirkIfNeeded(rectTransformationIntrospection: RectangleTransformationIntrospection, elementId: DiagramElementId, rect: Rectangle2D.Float, center: Point2D.Float, transformed: Rectangle2D.Float, halfWidth: Float, halfHeight: Float) { + if (rectTransformationIntrospection.type.nests || rectTransformationIntrospection.type == AreaType.SHAPE) { + fillRectangleQuirk(elementId, rect, Point2D.Float(center.x - transformed.x - halfWidth, center.y - transformed.y - halfHeight)) + } + } + + private fun fillRectangleQuirk(elementId: DiagramElementId, rect: Rectangle2D.Float, delta: Point2D.Float) { + quirkForRectangles[elementId] = RectangleQuirk( + Rectangle2D.Float( + rect.x - quirkEpsilon, + rect.y - quirkEpsilon, + rect.width + quirkEpsilon, + rect.height + quirkEpsilon + ), + delta + ) + } + private fun transformPoint(point: Point2D.Float): Point2D.Float { // assuming left-right, top-down coordinate system return when { abs(point.x - cx) < EPSILON && abs(point.y - cy) < EPSILON -> point - // rectangle edges: + // rectangle forming points: // top-left abs(point.x - shape.x) < EPSILON && abs(point.y - shape.y) < EPSILON -> Point2D.Float(point.x - dx, point.y - dy) // bottom-left @@ -278,40 +298,41 @@ class ViewTransformInverter { private val initialStepSize = 1.0f private val successMultiplier = 2.0f private val failMultiplier = 10.0f - private val diffStep = 1.0f + private val diffStep = 0.1f private val epsilon = 1.0f private val maxIter = 10 private val randomInitializationGuesses = 10 - private val randomInitializationAreaSpan = 100.0f + private val randomInitializationAreaSpan = 1000.0f + private val minQuirkDistSq = 100.0f /** * Minimizes (rect.x - transform(return.x)) ^ 2 + (rect.y - transform(return.y)) ^ 2 metric * shape changes are ignored so far */ - fun invert(elementId: DiagramElementId, target: Point2D.Float, initialGuess: Point2D.Float, batch: ViewTransformBatch): Point2D.Float { + fun invert(elementId: DiagramElementId, target: Point2D.Float, initialGuess: Point2D.Float, batch: ViewTransformBatch, introspection: PointTransformationIntrospection? = null): Point2D.Float { if (batch.isEmpty()) { return target } - return invert(elementId, target, initialGuess, batch, PointTransformationIntrospection()) + return doInvert(elementId, target, initialGuess, batch, introspection ?: PointTransformationIntrospection()) } /** * Minimizes (rect.x - transform(return.x)) ^ 2 + (rect.y - transform(return.y)) ^ 2 metric * shape changes are ignored so far */ - private fun invert(elementId: DiagramElementId, target: Point2D.Float, initialGuess: Point2D.Float, batch: ViewTransformBatch, introspection: PointTransformationIntrospection): Point2D.Float { - val range = 1..randomInitializationGuesses + private fun doInvert(elementId: DiagramElementId, target: Point2D.Float, initialGuess: Point2D.Float, batch: ViewTransformBatch, introspection: PointTransformationIntrospection): Point2D.Float { + val range = 0..randomInitializationGuesses fun randomFromAreaRange(): Float { return (nextFloat() * 2.0f - 1.0f) * randomInitializationAreaSpan } val result = range.map { - val guess = Point2D.Float(initialGuess.x - randomFromAreaRange(), initialGuess.y - randomFromAreaRange()) - minimizeGradientDescent(elementId, target, guess, batch, introspection) + val guess = if (0 != it) Point2D.Float(initialGuess.x - randomFromAreaRange(), initialGuess.y - randomFromAreaRange()) else initialGuess + minimizeGradientDescent(elementId, target, guess, batch, introspection.copy(selectCloseQuirkWithin = minQuirkDistSq)) } - return result.minBy { it: PointWithResidual -> it.residual }!!.point + return result.minBy { it.residual }!!.point } private fun minimizeGradientDescent(elementId: DiagramElementId, target: Point2D.Float, initialGuess: Point2D.Float, batch: ViewTransformBatch, introspection: PointTransformationIntrospection): PointWithResidual { @@ -352,4 +373,4 @@ class ViewTransformInverter { } private data class PointWithResidual(val point: Point2D.Float, val residual: Float) -} \ No newline at end of file +} diff --git a/build.gradle b/build.gradle index f13279474..c82a23b24 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.jetbrains.intellij' version '1.1.6' + id 'org.jetbrains.intellij' version '1.3.0' id 'org.jetbrains.kotlin.jvm' version '1.5.30' id 'org.jetbrains.kotlin.kapt' version '1.5.30' } @@ -8,6 +8,7 @@ plugins { ext { intellijPlatform = 'IU-2019.3' intellijPlatformPlugins = ['java', 'DatabaseTools'] // DatabaseTools is for BPMN process 'debugging' + runIdeJbrVersion = 'jbr_dcevm-11_0_13b1751.16' kotlinStdlib = '1.5.30' kotlinApiVersion = '1.3' // It must be same as JB supplied Kotlin STDLIB i.e. for 2018 = 1.3. See https://youtrack.jetbrains.com/issue/KT-37435 @@ -48,4 +49,4 @@ subprojects { tasks.withType(Test) { useJUnitPlatform() } -} \ No newline at end of file +} diff --git a/camunda-intellij-plugin/build.gradle b/camunda-intellij-plugin/build.gradle index 2f2849478..f27b9f8ad 100644 --- a/camunda-intellij-plugin/build.gradle +++ b/camunda-intellij-plugin/build.gradle @@ -42,6 +42,10 @@ intellij { plugins = intellijPlatformPlugins } +runIde { + jbrVersion = runIdeJbrVersion +} + publishPlugin { token = intellijPublishToken } @@ -82,4 +86,4 @@ jacocoTestReport { xml.enabled true csv.enabled false } -} \ No newline at end of file +} diff --git a/flowable-intellij-plugin/build.gradle b/flowable-intellij-plugin/build.gradle index 227c417f2..fe7c565ff 100644 --- a/flowable-intellij-plugin/build.gradle +++ b/flowable-intellij-plugin/build.gradle @@ -42,6 +42,10 @@ intellij { plugins = intellijPlatformPlugins } +runIde { + jbrVersion = runIdeJbrVersion +} + publishPlugin { token = intellijPublishToken } @@ -82,4 +86,4 @@ jacocoTestReport { xml.enabled true csv.enabled false } -} \ No newline at end of file +} diff --git a/flowable-xml-parser/src/test/resources/collapsed-subprocess.bpmn20.xml b/flowable-xml-parser/src/test/resources/collapsed-subprocess.bpmn20.xml new file mode 100644 index 000000000..eb4773ad1 --- /dev/null +++ b/flowable-xml-parser/src/test/resources/collapsed-subprocess.bpmn20.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file