Skip to content

Commit

Permalink
PAINTROID-432
Browse files Browse the repository at this point in the history
Implemented new "clipping" tool where user can mark one or several areas and then apply the tool which erases everything except the marked areas.
  • Loading branch information
Electronix1337 committed Jul 12, 2022
1 parent c87fb29 commit 520c87e
Show file tree
Hide file tree
Showing 32 changed files with 945 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,7 @@ class LayerIntegrationTest {
TopBarViewInteraction.onTopBarView()
.performOpenMoreOptions()
onView(withText(R.string.menu_load_image)).perform(click())
onView(withText(R.string.menu_replace_image)).perform(click())
Intents.release()
onView(withText(R.string.dialog_warning_new_image)).check(ViewAssertions.doesNotExist())
onView(withText(R.string.pocketpaint_ok)).perform(click())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,319 @@
package org.catrobat.paintroid.test.espresso.tools

import android.graphics.Color
import android.graphics.PointF
import androidx.test.espresso.IdlingRegistry
import androidx.test.espresso.idling.CountingIdlingResource
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.rule.ActivityTestRule
import org.catrobat.paintroid.MainActivity
import org.catrobat.paintroid.test.espresso.util.BitmapLocationProvider
import org.catrobat.paintroid.test.espresso.util.DrawingSurfaceLocationProvider
import org.catrobat.paintroid.test.espresso.util.UiInteractions
import org.catrobat.paintroid.test.espresso.util.wrappers.DrawingSurfaceInteraction
import org.catrobat.paintroid.test.espresso.util.wrappers.LayerMenuViewInteraction
import org.catrobat.paintroid.test.espresso.util.wrappers.ToolBarViewInteraction
import org.catrobat.paintroid.test.espresso.util.wrappers.ToolPropertiesInteraction.onToolProperties
import org.catrobat.paintroid.test.espresso.util.wrappers.TopBarViewInteraction
import org.catrobat.paintroid.test.utils.ScreenshotOnFailRule
import org.catrobat.paintroid.tools.ToolReference
import org.catrobat.paintroid.tools.ToolType
import org.catrobat.paintroid.tools.Workspace
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class ClippingToolIntegrationTest {
@get:Rule
var launchActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule(
MainActivity::class.java
)

@get:Rule
var screenshotOnFailRule = ScreenshotOnFailRule()

private lateinit var idlingResource: CountingIdlingResource
private lateinit var toolReference: ToolReference
private lateinit var mainActivity: MainActivity
private lateinit var workspace: Workspace
private lateinit var middle: PointF
private lateinit var middleLeft: PointF
private lateinit var middleTop: PointF
private lateinit var middleBot: PointF
private lateinit var middleRight: PointF

private lateinit var middlePoint1: PointF
private lateinit var middlePoint2: PointF
private lateinit var middlePoint3: PointF
private lateinit var middlePoint4: PointF

@Before
fun setUp() {
mainActivity = launchActivityRule.activity
idlingResource = mainActivity.idlingResource
IdlingRegistry.getInstance().register(idlingResource)
workspace = mainActivity.workspace
toolReference = mainActivity.toolReference
middle = PointF((workspace.width / 2).toFloat(), (workspace.height / 2).toFloat())
middleLeft = PointF(middle.x - workspace.width / 4, middle.y)
middleTop = PointF(middle.x, middle.y - workspace.height / 4)
middleBot = PointF(middle.x, middle.y + workspace.height / 4)
middleRight = PointF(middle.x + workspace.width / 4, middle.y)

middlePoint1 = PointF(middle.x - workspace.width / 4, middle.y - workspace.height / 4)
middlePoint2 = PointF(middle.x + workspace.width / 4, middle.y - workspace.height / 4)
middlePoint3 = PointF(middle.x + workspace.width / 4, middle.y + workspace.height / 4)
middlePoint4 = PointF(middle.x - workspace.width / 4, middle.y + workspace.height / 4)

ToolBarViewInteraction.onToolBarView()
.performSelectTool(ToolType.FILL)
}

@After
fun tearDown() {
IdlingRegistry.getInstance().unregister(idlingResource)
}

@Test
fun testClipOnBlackBitmap() {
onToolProperties().setColor(Color.BLACK)

DrawingSurfaceInteraction.onDrawingSurfaceView()
.checkPixelColor(Color.TRANSPARENT, BitmapLocationProvider.MIDDLE)

DrawingSurfaceInteraction.onDrawingSurfaceView()
.perform(UiInteractions.touchAt(DrawingSurfaceLocationProvider.MIDDLE))

DrawingSurfaceInteraction.onDrawingSurfaceView()
.checkPixelColor(Color.BLACK, BitmapLocationProvider.MIDDLE)

ToolBarViewInteraction.onToolBarView()
.performSelectTool(ToolType.CLIP)

onToolProperties().setColor(Color.YELLOW)

toolReference.tool?.handleDown(middleLeft)
toolReference.tool?.handleMove(middlePoint1)
toolReference.tool?.handleMove(middleTop)
toolReference.tool?.handleMove(middlePoint2)
toolReference.tool?.handleMove(middleRight)
toolReference.tool?.handleMove(middlePoint3)
toolReference.tool?.handleMove(middleBot)
toolReference.tool?.handleMove(middlePoint4)
toolReference.tool?.handleUp(middleLeft)

TopBarViewInteraction.onTopBarView()
.performClickCheckmark()

val inAreaX = middle.x - 10
val inAreaY = middle.y - 10

val outOfAreaX = workspace.width - 10
val outOfAreaY = workspace.height - 10

val colorInArea = workspace.bitmapOfCurrentLayer?.getPixel(inAreaX.toInt(), inAreaY.toInt())
val colorOutOfArea = workspace.bitmapOfCurrentLayer?.getPixel(outOfAreaX, outOfAreaY)

assertEquals(colorInArea, Color.BLACK)
assertEquals(colorOutOfArea, Color.TRANSPARENT)
}

@Test
fun testClipOnBlackBitmapOnlyAppliedOnCurrentLayer() {
onToolProperties().setColor(Color.BLACK)

DrawingSurfaceInteraction.onDrawingSurfaceView()
.checkPixelColor(Color.TRANSPARENT, BitmapLocationProvider.MIDDLE)

DrawingSurfaceInteraction.onDrawingSurfaceView()
.perform(UiInteractions.touchAt(DrawingSurfaceLocationProvider.MIDDLE))

DrawingSurfaceInteraction.onDrawingSurfaceView()
.checkPixelColor(Color.BLACK, BitmapLocationProvider.MIDDLE)

onToolProperties().setColor(Color.YELLOW)

LayerMenuViewInteraction.onLayerMenuView()
.performOpen()
.performAddLayer()
.performSelectLayer(0)
.performClose()

DrawingSurfaceInteraction.onDrawingSurfaceView()
.checkPixelColor(Color.TRANSPARENT, BitmapLocationProvider.MIDDLE)

DrawingSurfaceInteraction.onDrawingSurfaceView()
.perform(UiInteractions.touchAt(DrawingSurfaceLocationProvider.MIDDLE))

DrawingSurfaceInteraction.onDrawingSurfaceView()
.checkPixelColor(Color.YELLOW, BitmapLocationProvider.MIDDLE)

ToolBarViewInteraction.onToolBarView()
.performSelectTool(ToolType.CLIP)

toolReference.tool?.handleDown(middleLeft)
toolReference.tool?.handleMove(middlePoint1)
toolReference.tool?.handleMove(middleTop)
toolReference.tool?.handleMove(middlePoint2)
toolReference.tool?.handleMove(middleRight)
toolReference.tool?.handleMove(middlePoint3)
toolReference.tool?.handleMove(middleBot)
toolReference.tool?.handleMove(middlePoint4)
toolReference.tool?.handleUp(middleLeft)

TopBarViewInteraction.onTopBarView()
.performClickCheckmark()

val inAreaX = middle.x - 10
val inAreaY = middle.y - 10

val outOfAreaX = workspace.width - 10
val outOfAreaY = workspace.height - 10

val colorInAreaCurrentLayer = workspace.bitmapOfCurrentLayer?.getPixel(inAreaX.toInt(), inAreaY.toInt())
val colorOutOfAreaCurrentLayer = workspace.bitmapOfCurrentLayer?.getPixel(outOfAreaX, outOfAreaY)

val colorInAreaSecondLayer = workspace.bitmapLisOfAllLayers[1]?.getPixel(inAreaX.toInt(), inAreaY.toInt())
val colorOutOfAreaSecondLayer = workspace.bitmapLisOfAllLayers[1]?.getPixel(outOfAreaX, outOfAreaY)

assertEquals(colorInAreaCurrentLayer, Color.YELLOW)
assertEquals(colorOutOfAreaCurrentLayer, Color.TRANSPARENT)
assertEquals(colorInAreaSecondLayer, Color.BLACK)
assertEquals(colorOutOfAreaSecondLayer, Color.BLACK)
}

@Test
fun testIfPathGetsDrawnWhenUsingClippingTool() {
DrawingSurfaceInteraction.onDrawingSurfaceView()
.checkPixelColor(Color.TRANSPARENT, BitmapLocationProvider.MIDDLE)

ToolBarViewInteraction.onToolBarView()
.performSelectTool(ToolType.CLIP)

onToolProperties().setColor(Color.BLACK)

onToolProperties().setStrokeWidth(20f)

toolReference.tool?.handleDown(middleTop)
toolReference.tool?.handleMove(middleLeft)
toolReference.tool?.handleMove(middleRight)
toolReference.tool?.handleUp(middleTop)

LayerMenuViewInteraction.onLayerMenuView()
.performOpen()
.performClose()

val bitmapColor = workspace.bitmapOfCurrentLayer?.getPixel(middle.x.toInt(), middle.y.toInt())
assertEquals(bitmapColor, Color.BLACK)
}

@Test
fun testClipBlackBitmapAndThenUndo() {
onToolProperties().setColor(Color.BLACK)

DrawingSurfaceInteraction.onDrawingSurfaceView()
.checkPixelColor(Color.TRANSPARENT, BitmapLocationProvider.MIDDLE)

DrawingSurfaceInteraction.onDrawingSurfaceView()
.perform(UiInteractions.touchAt(DrawingSurfaceLocationProvider.MIDDLE))

DrawingSurfaceInteraction.onDrawingSurfaceView()
.checkPixelColor(Color.BLACK, BitmapLocationProvider.MIDDLE)

ToolBarViewInteraction.onToolBarView()
.performSelectTool(ToolType.CLIP)

onToolProperties().setColor(Color.YELLOW)

toolReference.tool?.handleDown(middleLeft)
toolReference.tool?.handleMove(middlePoint1)
toolReference.tool?.handleMove(middleTop)
toolReference.tool?.handleMove(middlePoint2)
toolReference.tool?.handleMove(middleRight)
toolReference.tool?.handleMove(middlePoint3)
toolReference.tool?.handleMove(middleBot)
toolReference.tool?.handleMove(middlePoint4)
toolReference.tool?.handleUp(middleLeft)

TopBarViewInteraction.onTopBarView()
.performClickCheckmark()

val inAreaX = middle.x - 10
val inAreaY = middle.y - 10

val outOfAreaX = workspace.width - 10
val outOfAreaY = workspace.height - 10

val colorInArea = workspace.bitmapOfCurrentLayer?.getPixel(inAreaX.toInt(), inAreaY.toInt())
val colorOutOfArea = workspace.bitmapOfCurrentLayer?.getPixel(outOfAreaX, outOfAreaY)

assertEquals(colorInArea, Color.BLACK)
assertEquals(colorOutOfArea, Color.TRANSPARENT)

TopBarViewInteraction.onTopBarView()
.performUndo()

val colorOutOfAreaAfterUndo = workspace.bitmapOfCurrentLayer?.getPixel(outOfAreaX, outOfAreaY)
assertEquals(colorOutOfAreaAfterUndo, Color.BLACK)
}

@Test
fun testClipBlackBitmapAndThenUndoAndRedo() {
onToolProperties().setColor(Color.BLACK)

DrawingSurfaceInteraction.onDrawingSurfaceView()
.checkPixelColor(Color.TRANSPARENT, BitmapLocationProvider.MIDDLE)

DrawingSurfaceInteraction.onDrawingSurfaceView()
.perform(UiInteractions.touchAt(DrawingSurfaceLocationProvider.MIDDLE))

DrawingSurfaceInteraction.onDrawingSurfaceView()
.checkPixelColor(Color.BLACK, BitmapLocationProvider.MIDDLE)

ToolBarViewInteraction.onToolBarView()
.performSelectTool(ToolType.CLIP)

onToolProperties().setColor(Color.YELLOW)

toolReference.tool?.handleDown(middleLeft)
toolReference.tool?.handleMove(middlePoint1)
toolReference.tool?.handleMove(middleTop)
toolReference.tool?.handleMove(middlePoint2)
toolReference.tool?.handleMove(middleRight)
toolReference.tool?.handleMove(middlePoint3)
toolReference.tool?.handleMove(middleBot)
toolReference.tool?.handleMove(middlePoint4)
toolReference.tool?.handleUp(middleLeft)

TopBarViewInteraction.onTopBarView()
.performClickCheckmark()

val inAreaX = middle.x - 10
val inAreaY = middle.y - 10

val outOfAreaX = workspace.width - 10
val outOfAreaY = workspace.height - 10

val colorInArea = workspace.bitmapOfCurrentLayer?.getPixel(inAreaX.toInt(), inAreaY.toInt())
val colorOutOfArea = workspace.bitmapOfCurrentLayer?.getPixel(outOfAreaX, outOfAreaY)

assertEquals(colorInArea, Color.BLACK)
assertEquals(colorOutOfArea, Color.TRANSPARENT)

TopBarViewInteraction.onTopBarView()
.performUndo()

val colorOutOfAreaAfterUndo = workspace.bitmapOfCurrentLayer?.getPixel(outOfAreaX, outOfAreaY)
assertEquals(colorOutOfAreaAfterUndo, Color.BLACK)

TopBarViewInteraction.onTopBarView()
.performRedo()

val colorOutOfAreaAfterRedo = workspace.bitmapOfCurrentLayer?.getPixel(outOfAreaX, outOfAreaY)
assertEquals(colorOutOfAreaAfterRedo, Color.TRANSPARENT)
}
}
13 changes: 10 additions & 3 deletions Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import org.catrobat.paintroid.tools.ToolReference
import org.catrobat.paintroid.tools.ToolType
import org.catrobat.paintroid.tools.Workspace
import org.catrobat.paintroid.tools.implementation.BaseToolWithShape
import org.catrobat.paintroid.tools.implementation.ClippingTool
import org.catrobat.paintroid.tools.implementation.DefaultContextCallback
import org.catrobat.paintroid.tools.implementation.DefaultToolFactory
import org.catrobat.paintroid.tools.implementation.DefaultToolPaint
Expand Down Expand Up @@ -447,7 +448,7 @@ class MainActivity : AppCompatActivity(), MainView, CommandListener {
defaultToolController = DefaultToolController(
toolReference,
toolOptionsViewController,
DefaultToolFactory(),
DefaultToolFactory(this),
commandManager,
workspace,
idlingResource,
Expand Down Expand Up @@ -536,9 +537,15 @@ class MainActivity : AppCompatActivity(), MainView, CommandListener {
topBar.checkmarkButton.setOnClickListener {
if (toolReference.tool?.toolType?.name.equals(ToolType.TRANSFORM.name)) {
(toolReference.tool as TransformTool).checkMarkClicked = true
val tool = toolReference.tool as BaseToolWithShape?
tool?.onClickOnButton()
} else if (toolReference.tool?.toolType?.name.equals(ToolType.CLIP.name)) {
val tool = toolReference.tool as ClippingTool?
tool?.onClickOnButton()
} else {
val tool = toolReference.tool as BaseToolWithShape?
tool?.onClickOnButton()
}
val tool = toolReference.tool as BaseToolWithShape?
tool?.onClickOnButton()
}
topBar.plusButton.setOnClickListener {
val tool = toolReference.tool as LineTool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,13 @@ interface CommandFactory {

fun createPathCommand(paint: Paint, path: SerializablePath): Command

fun createSmudgePathCommand(bitmap: Bitmap, pointPath: MutableList<PointF>, maxPressure: Float, maxSize: Float, minSize: Float): Command
fun createSmudgePathCommand(
bitmap: Bitmap,
pointPath: MutableList<PointF>,
maxPressure: Float,
maxSize: Float,
minSize: Float
): Command

fun createTextToolCommand(
multilineText: Array<String>,
Expand Down Expand Up @@ -109,4 +115,9 @@ interface CommandFactory {
): Command

fun createColorChangedCommand(toolReference: ToolReference, context: Context, color: Int): Command

fun createClippingCommand(
bitmap: Bitmap,
pathBitmap: Bitmap
): Command
}
Loading

0 comments on commit 520c87e

Please sign in to comment.