mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 01:08:50 -06:00
Implement HtmlCanvas; move some tests to commonTest
This commit is contained in:
@@ -1 +0,0 @@
|
||||
org.gradle.parallel=true
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
package org.isoron.platform.concurrency
|
||||
|
||||
import java.util.concurrent.*
|
||||
import kotlin.test.*
|
||||
|
||||
class ObservableTest {
|
||||
@@ -29,20 +28,19 @@ class ObservableTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test() {
|
||||
val latch = CountDownLatch(1)
|
||||
fun testNotifyListeners() {
|
||||
var wasCalled = false
|
||||
|
||||
val listener = object : TestListener {
|
||||
override fun onDataChanged(data: Int) {
|
||||
assertEquals(42, data)
|
||||
latch.countDown()
|
||||
wasCalled = true
|
||||
}
|
||||
}
|
||||
|
||||
val observable = Observable<TestListener>()
|
||||
observable.addListener(listener)
|
||||
observable.notifyListeners { l ->
|
||||
l.onDataChanged(42)
|
||||
}
|
||||
observable.removeListener(listener)
|
||||
assertTrue(latch.await(3, TimeUnit.SECONDS))
|
||||
observable.notifyListeners { it.onDataChanged(42) }
|
||||
assertTrue(wasCalled)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.platform.gui
|
||||
|
||||
class CanvasTest(val platform: Platform) {
|
||||
interface Platform {
|
||||
fun createCanvas(width: Int, height: Int): Canvas
|
||||
fun writePng(canvas: Canvas, filename: String)
|
||||
}
|
||||
|
||||
fun testDrawing() {
|
||||
val canvas = platform.createCanvas(500, 400)
|
||||
|
||||
canvas.setColor(Color(0x303030))
|
||||
canvas.fillRect(0.0, 0.0, 500.0, 400.0)
|
||||
|
||||
canvas.setColor(Color(0x606060))
|
||||
canvas.setStrokeWidth(25.0)
|
||||
canvas.drawRect(100.0, 100.0, 300.0, 200.0)
|
||||
|
||||
canvas.setColor(Color(0xFFFF00))
|
||||
canvas.setStrokeWidth(1.0)
|
||||
canvas.drawRect(0.0, 0.0, 100.0, 100.0)
|
||||
canvas.fillCircle(50.0, 50.0, 30.0)
|
||||
canvas.drawRect(0.0, 100.0, 100.0, 100.0)
|
||||
canvas.fillArc(50.0, 150.0, 30.0, 90.0, 135.0)
|
||||
canvas.drawRect(0.0, 200.0, 100.0, 100.0)
|
||||
canvas.fillArc(50.0, 250.0, 30.0, 90.0, -135.0)
|
||||
canvas.drawRect(0.0, 300.0, 100.0, 100.0)
|
||||
canvas.fillArc(50.0, 350.0, 30.0, 45.0, 90.0)
|
||||
|
||||
canvas.setColor(Color(0xFF0000))
|
||||
canvas.setStrokeWidth(2.0)
|
||||
canvas.drawLine(0.0, 0.0, 500.0, 400.0)
|
||||
canvas.drawLine(500.0, 0.0, 0.0, 400.0)
|
||||
|
||||
canvas.setFont(Font.BOLD)
|
||||
canvas.setFontSize(50.0)
|
||||
canvas.setColor(Color(0x00FF00))
|
||||
canvas.setTextAlign(TextAlign.CENTER)
|
||||
canvas.drawText("HELLO", 250.0, 100.0)
|
||||
|
||||
canvas.setTextAlign(TextAlign.RIGHT)
|
||||
canvas.drawText("HELLO", 250.0, 150.0)
|
||||
|
||||
canvas.setTextAlign(TextAlign.LEFT)
|
||||
canvas.drawText("HELLO", 250.0, 200.0)
|
||||
|
||||
canvas.setFont(Font.FONT_AWESOME)
|
||||
canvas.drawText(FontAwesome.CHECK, 250.0, 300.0)
|
||||
|
||||
platform.writePng(canvas, "CanvasTest.png")
|
||||
}
|
||||
}
|
||||
@@ -20,14 +20,12 @@
|
||||
package org.isoron.uhabits.models
|
||||
|
||||
import org.isoron.platform.time.*
|
||||
import org.isoron.uhabits.*
|
||||
import org.isoron.uhabits.models.Checkmark.Companion.CHECKED_AUTOMATIC
|
||||
import org.isoron.uhabits.models.Checkmark.Companion.CHECKED_MANUAL
|
||||
import org.isoron.uhabits.models.Checkmark.Companion.UNCHECKED
|
||||
import org.junit.Test
|
||||
import kotlin.test.*
|
||||
|
||||
class CheckmarkListTest : BaseTest() {
|
||||
class CheckmarkListTest {
|
||||
|
||||
private val today = LocalDate(2019, 1, 30)
|
||||
|
||||
110
core/src/jsMain/kotlin/org/isoron/platform/gui/HtmlCanvas.kt
Normal file
110
core/src/jsMain/kotlin/org/isoron/platform/gui/HtmlCanvas.kt
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.platform.gui
|
||||
|
||||
import org.w3c.dom.*
|
||||
import kotlin.browser.*
|
||||
import kotlin.math.*
|
||||
|
||||
class HtmlCanvas(val canvas: HTMLCanvasElement) : Canvas {
|
||||
|
||||
val ctx = canvas.getContext("2d") as CanvasRenderingContext2D
|
||||
var fontSize = 12.0
|
||||
var fontWeight = ""
|
||||
var fontFamily = "sans-serif"
|
||||
var align = CanvasTextAlign.CENTER
|
||||
|
||||
override fun setColor(color: Color) {
|
||||
val c = "rgb(${color.red * 255}, ${color.green * 255}, ${color.blue * 255})"
|
||||
ctx.fillStyle = c;
|
||||
ctx.strokeStyle = c;
|
||||
}
|
||||
|
||||
override fun drawLine(x1: Double, y1: Double, x2: Double, y2: Double) {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(x1 + 0.5, y1 + 0.5)
|
||||
ctx.lineTo(x2 + 0.5, y2 + 0.5)
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
override fun drawText(text: String, x: Double, y: Double) {
|
||||
ctx.font = "${fontWeight} ${fontSize}px ${fontFamily}"
|
||||
ctx.textAlign = align
|
||||
ctx.textBaseline = CanvasTextBaseline.MIDDLE
|
||||
ctx.fillText(text, x, y)
|
||||
}
|
||||
|
||||
override fun fillRect(x: Double, y: Double, width: Double, height: Double) {
|
||||
ctx.fillRect(x - 0.5, y - 0.5, width + 1.0, height + 1.0)
|
||||
}
|
||||
|
||||
override fun drawRect(x: Double, y: Double, width: Double, height: Double) {
|
||||
ctx.strokeRect(x - 0.5, y - 0.5, width + 1.0, height + 1.0)
|
||||
}
|
||||
|
||||
override fun getHeight(): Double {
|
||||
return canvas.height.toDouble()
|
||||
}
|
||||
|
||||
override fun getWidth(): Double {
|
||||
return canvas.width.toDouble()
|
||||
}
|
||||
|
||||
override fun setFont(font: Font) {
|
||||
fontWeight = if (font == Font.BOLD) "bold" else ""
|
||||
fontFamily = if (font == Font.FONT_AWESOME) "FontAwesome" else "sans-serif"
|
||||
}
|
||||
|
||||
override fun setFontSize(size: Double) {
|
||||
fontSize = size
|
||||
}
|
||||
|
||||
override fun setStrokeWidth(size: Double) {
|
||||
ctx.lineWidth = size
|
||||
}
|
||||
|
||||
override fun fillArc(centerX: Double,
|
||||
centerY: Double,
|
||||
radius: Double,
|
||||
startAngle: Double,
|
||||
swipeAngle: Double) {
|
||||
val from = startAngle / 180 * PI
|
||||
val to = (startAngle + swipeAngle) / 180 * PI
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(centerX, centerY)
|
||||
ctx.arc(centerX, centerY, radius, -from, -to, swipeAngle >= 0)
|
||||
ctx.lineTo(centerX, centerY)
|
||||
ctx.fill()
|
||||
}
|
||||
|
||||
override fun fillCircle(centerX: Double, centerY: Double, radius: Double) {
|
||||
ctx.beginPath()
|
||||
ctx.arc(centerX, centerY, radius, 0.0, 2 * PI)
|
||||
ctx.fill()
|
||||
}
|
||||
|
||||
override fun setTextAlign(align: TextAlign) {
|
||||
this.align = when(align) {
|
||||
TextAlign.LEFT -> CanvasTextAlign.LEFT
|
||||
TextAlign.CENTER -> CanvasTextAlign.CENTER
|
||||
TextAlign.RIGHT -> CanvasTextAlign.RIGHT
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2019 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* This file is part of Loop Habit Tracker.
|
||||
*
|
||||
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.platform.gui
|
||||
|
||||
import org.w3c.dom.*
|
||||
|
||||
class HtmlCanvasTest(val canvas: HTMLCanvasElement) : CanvasTest.Platform {
|
||||
|
||||
override fun createCanvas(width: Int, height: Int): Canvas {
|
||||
return HtmlCanvas(canvas)
|
||||
}
|
||||
|
||||
override fun writePng(canvas: Canvas, filename: String) {
|
||||
}
|
||||
|
||||
fun testDrawing() {
|
||||
val test = CanvasTest(this)
|
||||
test.testDrawing()
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import org.isoron.platform.io.*
|
||||
import java.awt.*
|
||||
import java.awt.RenderingHints.*
|
||||
import java.awt.font.*
|
||||
import java.awt.image.*
|
||||
import kotlin.math.*
|
||||
|
||||
fun createFont(path: String): java.awt.Font {
|
||||
@@ -34,15 +35,16 @@ private val NOTO_REGULAR_FONT = createFont("fonts/NotoSans-Regular.ttf")
|
||||
private val NOTO_BOLD_FONT = createFont("fonts/NotoSans-Bold.ttf")
|
||||
private val FONT_AWESOME_FONT = createFont("fonts/FontAwesome.ttf")
|
||||
|
||||
class JavaCanvas(val g2d: Graphics2D,
|
||||
val widthPx: Int,
|
||||
val heightPx: Int,
|
||||
class JavaCanvas(val image: BufferedImage,
|
||||
val pixelScale: Double = 2.0) : Canvas {
|
||||
|
||||
private val frc = FontRenderContext(null, true, true)
|
||||
private var fontSize = 12.0
|
||||
private var font = Font.REGULAR
|
||||
private var textAlign = TextAlign.CENTER
|
||||
val widthPx = image.width
|
||||
val heightPx = image.height
|
||||
val g2d = image.createGraphics()
|
||||
|
||||
init {
|
||||
g2d.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
|
||||
|
||||
@@ -26,50 +26,19 @@ import java.io.*
|
||||
import javax.imageio.*
|
||||
|
||||
|
||||
class JavaCanvasTest {
|
||||
class JavaCanvasTest : CanvasTest.Platform {
|
||||
private val commonTest = CanvasTest(this)
|
||||
|
||||
@Test
|
||||
fun testDrawing() {
|
||||
val image = BufferedImage(500, 400, BufferedImage.TYPE_INT_RGB)
|
||||
val canvas = JavaCanvas(image.createGraphics(), 500, 400, pixelScale=1.0)
|
||||
fun testDrawing() = commonTest.testDrawing()
|
||||
|
||||
canvas.setColor(Color(0x303030))
|
||||
canvas.fillRect(0.0, 0.0, 500.0, 400.0)
|
||||
override fun createCanvas(width: Int, height: Int): Canvas {
|
||||
val image = BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
|
||||
return JavaCanvas(image, pixelScale=1.0)
|
||||
}
|
||||
|
||||
canvas.setColor(Color(0x606060))
|
||||
canvas.setStrokeWidth(25.0)
|
||||
canvas.drawRect(100.0, 100.0, 300.0, 200.0)
|
||||
|
||||
canvas.setColor(Color(0xFFFF00))
|
||||
canvas.setStrokeWidth(1.0)
|
||||
canvas.drawRect(0.0, 0.0, 100.0, 100.0)
|
||||
canvas.fillCircle(50.0, 50.0, 30.0)
|
||||
canvas.drawRect(0.0, 100.0, 100.0, 100.0)
|
||||
canvas.fillArc(50.0, 150.0, 30.0, 90.0, 135.0)
|
||||
canvas.drawRect(0.0, 200.0, 100.0, 100.0)
|
||||
canvas.fillArc(50.0, 250.0, 30.0, 90.0, -135.0)
|
||||
canvas.drawRect(0.0, 300.0, 100.0, 100.0)
|
||||
canvas.fillArc(50.0, 350.0, 30.0, 45.0, 90.0)
|
||||
|
||||
canvas.setColor(Color(0xFF0000))
|
||||
canvas.setStrokeWidth(2.0)
|
||||
canvas.drawLine(0.0, 0.0, 500.0, 400.0)
|
||||
canvas.drawLine(500.0, 0.0, 0.0, 400.0)
|
||||
|
||||
canvas.setFont(Font.BOLD)
|
||||
canvas.setFontSize(50.0)
|
||||
canvas.setColor(Color(0x00FF00))
|
||||
canvas.setTextAlign(TextAlign.CENTER)
|
||||
canvas.drawText("HELLO", 250.0, 100.0)
|
||||
|
||||
canvas.setTextAlign(TextAlign.RIGHT)
|
||||
canvas.drawText("HELLO", 250.0, 150.0)
|
||||
|
||||
canvas.setTextAlign(TextAlign.LEFT)
|
||||
canvas.drawText("HELLO", 250.0, 200.0)
|
||||
|
||||
canvas.setFont(Font.FONT_AWESOME)
|
||||
canvas.drawText(FontAwesome.CHECK, 250.0, 300.0)
|
||||
|
||||
ImageIO.write(image, "png", File("/tmp/JavaCanvasTest.png"))
|
||||
override fun writePng(canvas: Canvas, filename: String) {
|
||||
val javaCanvas = canvas as JavaCanvas
|
||||
ImageIO.write(javaCanvas.image, "png", File("/tmp/JavaCanvasTest.png"))
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ open class BaseViewTest {
|
||||
component: Component,
|
||||
threshold: Double = 1e-3) {
|
||||
val actual = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
|
||||
val canvas = JavaCanvas(actual.createGraphics(), width, height)
|
||||
val canvas = JavaCanvas(actual)
|
||||
val expectedFile: JavaResourceFile
|
||||
val actualPath = "/tmp/${expectedPath}"
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ import UIKit
|
||||
class IosCanvasTest : XCTestCase {
|
||||
func testDraw() {
|
||||
UIGraphicsBeginImageContext(CGSize(width: 500, height: 400))
|
||||
|
||||
let canvas = IosCanvas(withBounds: CGRect(x: 0, y: 0, width: 500, height: 400))
|
||||
|
||||
canvas.setColor(color: Color(rgb: 0x303030))
|
||||
canvas.fillRect(x: 0.0, y: 0.0, width: 500.0, height: 400.0)
|
||||
|
||||
|
||||
@@ -10,12 +10,10 @@ core:
|
||||
|
||||
$(test_bundle): test/index.js core
|
||||
mkdir -p build/bundles
|
||||
npx webpack $< --silent --mode production --output $@
|
||||
npx webpack $< --silent --mode development --target web --output $@
|
||||
|
||||
test: $(test_bundle) $(node_modules)
|
||||
mkdir -p build/reports
|
||||
npx mocha $@ --reporter xunit > build/reports/tests.xml
|
||||
npx mocha $@
|
||||
open test/index.html
|
||||
|
||||
clean:
|
||||
rm -rf build
|
||||
|
||||
5
web/package-lock.json
generated
5
web/package-lock.json
generated
@@ -2231,6 +2231,11 @@
|
||||
"readable-stream": "^2.3.6"
|
||||
}
|
||||
},
|
||||
"fontawesome": {
|
||||
"version": "5.6.3",
|
||||
"resolved": "https://registry.npmjs.org/fontawesome/-/fontawesome-5.6.3.tgz",
|
||||
"integrity": "sha512-FCc+CawwsJWWprVEg9X14yI7zI+l9YVAyhzgu70qwGeDn0tLLDH/dVfqgij72g4BBGgLGfK2qnvFGAmYUkhaWg=="
|
||||
},
|
||||
"for-in": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
||||
|
||||
BIN
web/test/FontAwesome.ttf
Normal file
BIN
web/test/FontAwesome.ttf
Normal file
Binary file not shown.
21
web/test/canvas.html
Normal file
21
web/test/canvas.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Canvas Test</title>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: "FontAwesome";
|
||||
src: url(FontAwesome.ttf) format("truetype");
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script src="../build/bundles/test.js"></script>
|
||||
<canvas id="canvas" width=500 height=400></canvas>
|
||||
<script>
|
||||
const canvas = document.getElementById('canvas');
|
||||
const test = new document.coreTest.org.isoron.platform.gui.HtmlCanvasTest(canvas);
|
||||
test.testDrawing();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
15
web/test/index.html
Normal file
15
web/test/index.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Mocha Tests</title>
|
||||
<link rel="stylesheet" href="../node_modules/mocha/mocha.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
<script src="../node_modules/mocha/mocha.js"></script>
|
||||
<script src="../node_modules/chai/chai.js"></script>
|
||||
<script>mocha.setup('bdd')</script>
|
||||
<script src="../build/bundles/test.js"></script>
|
||||
<script>mocha.run();</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,2 +1,3 @@
|
||||
var assert = require('assert');
|
||||
var coreTest = require('core_test');
|
||||
document.coreTest = coreTest
|
||||
|
||||
Reference in New Issue
Block a user