Skip to content

Commit 0bc32bf

Browse files
committed
PAINTROID-396 Multiline tool with movable intermediate points
1 parent b34cc9b commit 0bc32bf

File tree

5 files changed

+119
-17
lines changed

5 files changed

+119
-17
lines changed

Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/tools/DynamicLineToolIntegrationTest.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ class DynamicLineToolIntegrationTest {
3939

4040
@Test
4141
fun testIfCurrentToolIsShownInBottomNavigation() {
42-
ToolBarViewInteraction.onToolBarView().performSelectTool(ToolType.DYNALINE)
43-
BottomNavigationViewInteraction.onBottomNavigationView().checkShowsCurrentTool(ToolType.DYNALINE)
44-
42+
ToolBarViewInteraction.onToolBarView().performSelectTool(ToolType.DYNAMICLINE)
43+
BottomNavigationViewInteraction.onBottomNavigationView().checkShowsCurrentTool(ToolType.DYNAMICLINE)
4544
}
4645
}

Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt

+10-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,16 @@ import org.catrobat.paintroid.tools.ToolPaint
8282
import org.catrobat.paintroid.tools.ToolReference
8383
import org.catrobat.paintroid.tools.ToolType
8484
import org.catrobat.paintroid.tools.Workspace
85-
import org.catrobat.paintroid.tools.implementation.*
85+
import org.catrobat.paintroid.tools.implementation.BaseToolWithShape
86+
import org.catrobat.paintroid.tools.implementation.ClippingTool
87+
import org.catrobat.paintroid.tools.implementation.DefaultContextCallback
88+
import org.catrobat.paintroid.tools.implementation.DefaultToolFactory
89+
import org.catrobat.paintroid.tools.implementation.DefaultToolPaint
90+
import org.catrobat.paintroid.tools.implementation.DefaultToolReference
91+
import org.catrobat.paintroid.tools.implementation.DefaultWorkspace
92+
import org.catrobat.paintroid.tools.implementation.LineTool
93+
import org.catrobat.paintroid.tools.implementation.TransformTool
94+
import org.catrobat.paintroid.tools.implementation.DynamicLineTool
8695
import org.catrobat.paintroid.tools.options.ToolOptionsViewController
8796
import org.catrobat.paintroid.ui.DrawingSurface
8897
import org.catrobat.paintroid.ui.KeyboardListener

Paintroid/src/main/java/org/catrobat/paintroid/command/implementation/PathCommand.kt

+4
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,8 @@ class PathCommand(val paint: Paint, path: Path) : Command {
3636
override fun freeResources() {
3737
// No resources to free
3838
}
39+
40+
fun updatePath(newPath: Path) {
41+
this.path = newPath
42+
}
3943
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package org.catrobat.paintroid.tools.helper
2+
3+
import android.graphics.Color
4+
import android.graphics.Paint
5+
import android.graphics.PointF
6+
import android.graphics.RectF
7+
import org.catrobat.paintroid.command.Command
8+
9+
const val VERTEX_WIDTH = 30.0f
10+
11+
class DynamicLineToolVertex(vertexCenter: PointF?, outgoingPathCommand: Command?, ingoingPathCommand: Command?) {
12+
var vertexCenter: PointF? = vertexCenter
13+
var vertex: RectF? = null
14+
var outgoingPathCommand: Command? = outgoingPathCommand
15+
var ingoingPathCommand: Command? = ingoingPathCommand
16+
17+
init {
18+
if (vertexCenter != null) {
19+
vertex = RectF(
20+
vertexCenter.x - VERTEX_WIDTH,
21+
vertexCenter.y - VERTEX_WIDTH,
22+
vertexCenter.x + VERTEX_WIDTH,
23+
vertexCenter.y + VERTEX_WIDTH
24+
)
25+
}
26+
}
27+
28+
fun updateVertex(newCenter: PointF) {
29+
vertexCenter = newCenter
30+
vertex = RectF(
31+
newCenter.x - VERTEX_WIDTH,
32+
newCenter.y - VERTEX_WIDTH,
33+
newCenter.x + VERTEX_WIDTH,
34+
newCenter.y + VERTEX_WIDTH
35+
)
36+
}
37+
38+
companion object {
39+
private const val RECT_PAINT_ALPHA = 128
40+
private const val RECT_PAINT_STROKE_WIDTH = 2f
41+
42+
fun getPaint(): Paint {
43+
val paint = Paint()
44+
paint.run {
45+
style = Paint.Style.FILL
46+
color = Color.GRAY
47+
alpha = RECT_PAINT_ALPHA
48+
strokeWidth = RECT_PAINT_STROKE_WIDTH
49+
}
50+
return paint
51+
}
52+
53+
fun isInsideVertex(clickedCoordinate: PointF, rectF: RectF): Boolean =
54+
clickedCoordinate.x < rectF.right &&
55+
rectF.left < clickedCoordinate.x &&
56+
clickedCoordinate.y < rectF.bottom &&
57+
rectF.top < clickedCoordinate.y
58+
}
59+
}

Paintroid/src/main/java/org/catrobat/paintroid/tools/implementation/DynamicLineTool.kt

+44-13
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,28 @@ package org.catrobat.paintroid.tools.implementation
22

33
import android.graphics.Canvas
44
import android.graphics.Paint
5+
import android.graphics.Path
56
import android.graphics.PointF
67
import android.util.Log
78
import android.view.View
89
import androidx.test.espresso.idling.CountingIdlingResource
9-
import org.catrobat.paintroid.MainActivity
1010
import org.catrobat.paintroid.command.CommandManager
11+
import org.catrobat.paintroid.command.implementation.PathCommand
12+
import org.catrobat.paintroid.command.serialization.SerializablePath
1113
import org.catrobat.paintroid.tools.ContextCallback
1214
import org.catrobat.paintroid.tools.ToolPaint
1315
import org.catrobat.paintroid.tools.ToolType
1416
import org.catrobat.paintroid.tools.Workspace
1517
import org.catrobat.paintroid.tools.common.CommonBrushChangedListener
1618
import org.catrobat.paintroid.tools.common.CommonBrushPreviewListener
19+
import org.catrobat.paintroid.tools.helper.DynamicLineToolVertex
1720
import org.catrobat.paintroid.tools.options.BrushToolOptionsView
1821
import org.catrobat.paintroid.tools.options.ToolOptionsViewController
1922
import org.catrobat.paintroid.ui.viewholder.TopBarViewHolder
23+
import java.util.*
24+
import java.util.ArrayDeque
2025

21-
class DynamicLineTool (
26+
class DynamicLineTool(
2227
private val brushToolOptionsView: BrushToolOptionsView,
2328
contextCallback: ContextCallback,
2429
toolOptionsViewController: ToolOptionsViewController,
@@ -36,9 +41,12 @@ class DynamicLineTool (
3641
commandManager
3742
) {
3843
override var toolType: ToolType = ToolType.DYNAMICLINE
39-
var startCoordinate: PointF? = null
40-
var endCoordinate: PointF? = null
41-
var startCoordinateIsSet: Boolean = false
44+
private var startCoordinate: PointF? = null
45+
private var endCoordinate: PointF? = null
46+
private var startCoordinateIsSet: Boolean = false
47+
private var vertexStack: Deque<DynamicLineToolVertex> = ArrayDeque()
48+
private var lineIsFinal: Boolean = false
49+
private var currentPathCommand: PathCommand? = null
4250

4351
init {
4452
brushToolOptionsView.setBrushChangedListener(CommonBrushChangedListener(this))
@@ -51,7 +59,6 @@ class DynamicLineTool (
5159
brushToolOptionsView.setCurrentPaint(toolPaint.paint)
5260
brushToolOptionsView.setStrokeCapButtonChecked(toolPaint.strokeCap)
5361
topBarViewHolder?.hidePlusButton()
54-
5562
}
5663

5764
override fun handleUpAnimations(coordinate: PointF?) {
@@ -85,11 +92,15 @@ class DynamicLineTool (
8592
override fun onClickOnButton() {
8693
Log.e(TAG, " ✓ clicked")
8794
startCoordinateIsSet = false
95+
lineIsFinal = true
96+
currentPathCommand = null
8897
}
8998

9099
fun onClickOnPlus() {
100+
startCoordinate = endCoordinate?.let { copyPointF(it) }
101+
lineIsFinal = true
102+
currentPathCommand = null
91103
Log.e(TAG, "+ clicked")
92-
93104
}
94105

95106
private fun hideToolOptions() {
@@ -135,28 +146,41 @@ class DynamicLineTool (
135146
override fun handleDown(coordinate: PointF?): Boolean {
136147
coordinate ?: return false
137148
topBarViewHolder?.showPlusButton()
149+
super.handleDown(coordinate)
138150
startCoordinate = if (!startCoordinateIsSet) {
139151
copyPointF(coordinate).also { startCoordinateIsSet = true }
140152
} else {
141153
startCoordinate
142154
}
143-
super.handleDown(coordinate)
144155
return true
145156
}
146157

147158
override fun handleMove(coordinate: PointF?): Boolean {
148159
coordinate ?: return false
149160
hideToolOptions()
150161
super.handleMove(coordinate)
151-
152162
endCoordinate = copyPointF(coordinate)
153-
Log.e(TAG, endCoordinate!!.x.toString() + " " + endCoordinate!!.y.toString())
163+
Log.e(TAG, "Startcoordinate x: " + startCoordinate!!.x.toString() + " y: " + startCoordinate!!.y.toString())
164+
Log.e(TAG, "Endcoordinate x: " + endCoordinate!!.x.toString() + " y: " + endCoordinate!!.y.toString())
154165
return true
155166
}
156167

157168
override fun handleUp(coordinate: PointF?): Boolean {
169+
coordinate ?: return false
158170
showToolOptions()
159171
super.handleUp(coordinate)
172+
173+
var currentlyDrawnPath = createPath(startCoordinate, coordinate)
174+
// This would mean we are updating an existing path
175+
if (currentPathCommand != null) {
176+
// either update an existing command
177+
(currentPathCommand as PathCommand).updatePath(currentlyDrawnPath)
178+
commandManager.executeAllCommands()
179+
} else {
180+
// or create a new one
181+
currentPathCommand = commandFactory.createPathCommand(toolPaint.paint, currentlyDrawnPath) as PathCommand
182+
commandManager.addCommand(currentPathCommand)
183+
}
160184
return true
161185
}
162186

@@ -175,12 +199,19 @@ class DynamicLineTool (
175199
brushToolOptionsView.invalidate()
176200
}
177201

178-
private fun copyPointF(coordinate: PointF): PointF{
179-
return PointF(coordinate.x, coordinate.y)
202+
private fun copyPointF(coordinate: PointF): PointF = PointF(coordinate.x, coordinate.y)
203+
204+
private fun createPath(startCoordinate: PointF?, endCoordinate: PointF): SerializablePath {
205+
return SerializablePath().apply {
206+
if (startCoordinate != null && endCoordinate != null) {
207+
moveTo(startCoordinate.x, startCoordinate.y)
208+
lineTo(endCoordinate.x, endCoordinate.y)
209+
}
210+
}
180211
}
181212

182213
companion object {
183214
var topBarViewHolder: TopBarViewHolder? = null
184215
const val TAG = "DynamicLineTool"
185216
}
186-
}
217+
}

0 commit comments

Comments
 (0)