Add Hsla color functions, v. 0.3.10-SNAPSHOT

This commit is contained in:
2021-02-24 10:57:00 +01:00
parent dedbce0fa0
commit 2928a70728
10 changed files with 482 additions and 83 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
build
.idea
local.properties
gradle.properties

View File

@@ -1,12 +1,10 @@
import org.jetbrains.kotlin.fir.declarations.builder.buildResolvedImport
plugins {
kotlin("multiplatform") version "1.4.0-rc"
kotlin("multiplatform") version "1.4.30"
`maven-publish`
}
group = "nl.astraeus"
version = "0.3.6-SNAPSHOT"
version = "0.3.10-SNAPSHOT"
repositories {
maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") }
@@ -17,21 +15,36 @@ repositories {
kotlin {
jvm()
js(BOTH) {
browser()
//produceKotlinLibrary()
}
val hostOs = System.getProperty("os.name")
val isMingwX64 = hostOs.startsWith("Windows")
val nativeTarget = when {
hostOs == "Mac OS X" -> macosX64("native")
hostOs == "Linux" -> linuxX64("native")
isMingwX64 -> mingwX64("native")
else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
browser {
testTask {
useKarma {
useFirefox()
//useChrome()
}
}
}
}
sourceSets {
val commonMain by getting {}
val commonMain by getting {
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val jvmTest by getting {
dependencies {
implementation(kotlin("test-junit"))
}
}
val jsTest by getting {
dependencies {
implementation(kotlin("test-js"))
}
}
}
}
@@ -68,3 +81,4 @@ publishing {
}
}
}

View File

@@ -1,6 +1,5 @@
kotlin.code.style=official
kotlin.js.compiler=both
nexusUsername=
nexusPassword=
nexusUsername=deployment
nexusPassword=nhPTzBWizph86j2Jz5KhPdiB4C

View File

@@ -1,9 +1,13 @@
package nl.astraeus.css.properties
class Color(
value: String,
val readOnly: Boolean = true
import kotlin.math.max
import kotlin.math.min
open class Color(
value: String,
val readOnly: Boolean = false
) : CssProperty(value) {
/* val hue: Int? = null
val saturation: Int? = null
val lightness: Int? = null
@@ -41,42 +45,46 @@ class Color(
return this
}*/
companion object {
val auto = Color("auto")
val transparant = Color("transparant")
val initial = Color("initial")
val inherit = Color("inherit")
fun hex(hex: String) = Color("#$hex")
fun rgb(
red: Int,
green: Int,
blue: Int
) = Color("rgb($red, $green, $blue)")
fun rgba(
red: Int,
green: Int,
blue: Int,
alpha: Double
) = Color("rgba($red, $green, $blue, $alpha)")
fun hsl(
hue: Int,
saturation: Int,
lightness: Int
) = Color("hsl($hue, $saturation%, $lightness%)")
fun hsla(
hue: Int,
saturation: Int,
lightness: Int,
alpha: Double
) = Color("hsla($hue, $saturation%, $lightness%, $alpha)")
companion object {
val auto = Color("auto", true)
val transparant = Color("transparant", true)
val initial = Color("initial", true)
val inherit = Color("inherit", true)
private fun fromHex(
red: Int,
green: Int,
blue: Int
) {
fun hex(hex: String) = Color("#$hex")
fun rgb(
red: Int,
green: Int,
blue: Int
) = Color("rgb($red, $green, $blue)")
fun rgba(
red: Int,
green: Int,
blue: Int,
alpha: Double
) = Color("rgba($red, $green, $blue, $alpha)")
fun hsl(
hue: Int,
saturation: Int,
lightness: Int
) = Color("hsl($hue, $saturation%, $lightness%)")
fun hsla(
hue: Int,
saturation: Int,
lightness: Int,
alpha: Double
) = Color("hsla($hue, $saturation%, $lightness%, $alpha)")
private fun fromHex(
red: Int,
green: Int,
blue: Int
) {
}
}
}
}

View File

@@ -5,7 +5,7 @@ interface CssValue {
}
open class CssProperty(
val value: String
var value: String
): CssValue {
override fun css(): String = value

View File

@@ -0,0 +1,168 @@
package nl.astraeus.css.properties
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
class HslaColor(
val hue: Int,
val saturation: Int,
val lightness: Int,
val alpha: Double = 1.0
): Color("hsla($hue,$saturation%,$lightness%,$alpha)") {
fun darken(amount: Int): HslaColor = HslaColor(
hue,
saturation,
max(0, lightness - amount),
alpha
)
fun lighten(amount: Int): HslaColor = HslaColor(
hue,
saturation,
min(100, lightness + amount),
alpha
)
fun saturize(amount: Int): HslaColor = HslaColor(
hue,
min(100, saturation + amount),
lightness,
alpha
)
fun desaturize(amount: Int): HslaColor = HslaColor(
hue,
max(0, saturation - amount),
lightness,
alpha
)
fun adjustHue(amount: Int): HslaColor {
var hue = this.hue + amount
while (hue < 0) {
hue += 360
}
while(hue > 359) {
hue -= 360
}
return HslaColor(
hue,
saturation,
lightness,
alpha
)
}
fun toRgba() = RgbaColor.fromHsla(this)
companion object {
private fun findValues(value: String, expectedNumber: Int): List<String> {
check(value.contains('(') && value.contains(')'))
val parts = value.split('(')[1].split(')')[0].split(',')
check(parts.size == expectedNumber)
return parts
}
fun fromString(value: String): HslaColor = when {
value.trim().startsWith("#") -> {
fromHex(value.substringAfterLast('#'))
}
value.trim().startsWith("hsla") -> {
val values = findValues(value, 4)
HslaColor(
values[0].trim().toInt(),
values[1].trim().toInt(),
values[2].trim().toInt(),
values[3].trim().toDouble()
)
}
value.trim().startsWith("hsl") -> {
val values = findValues(value, 3)
HslaColor(
values[0].trim().toInt(),
values[1].trim().toInt(),
values[2].trim().toInt()
)
}
value.trim().startsWith("rgba") -> {
val values = findValues(value, 4)
fromRgba(
values[0].trim().toInt(),
values[1].trim().toInt(),
values[2].trim().toInt(),
values[3].trim().toDouble()
)
}
value.trim().startsWith("rgb") -> {
val values = findValues(value, 3)
fromRgb(
values[0].trim().toInt(),
values[1].trim().toInt(),
values[2].trim().toInt()
)
}
else -> {
throw IllegalArgumentException("Unable to parse $value as color")
}
}
fun fromHex(value: String): HslaColor = fromRgba(RgbaColor.fromHex(value))
fun fromRgba(rgba: RgbaColor): HslaColor = fromRgba(rgba.red, rgba.green, rgba.blue, rgba.alpha)
fun fromRgb(
red: Int,
green: Int,
blue: Int,
): HslaColor {
return fromRgba(red, green, blue, 1.0)
}
fun fromRgba(
red: Int,
green: Int,
blue: Int,
alpha: Double
): HslaColor {
val r = red / 255.0
val g = green / 255.0
val b = blue / 255.0
val v = max(r,max(g,b))
val c = v - min(r,min(g,b))
val f = (1 - abs(v+v-c-1))
var h = if (c > 0) {
when (v) {
r -> {
(g-b)/c
}
g -> {
2+(b-r)/c
}
else -> {
2+(b-r)/c
}
}
} else {
0.0
}
if (h < 0) {
h += 6
}
return HslaColor(
(60*h).toInt(),
if (f>0) { ((c * 100)/f).toInt() } else { 0 },
(100*((v+v-c)/2)).toInt(),
alpha
)
}
}
}

View File

@@ -11,28 +11,41 @@ open class Measurement(
val normal = Measurement("normal")
fun px(nr: Int) = if (nr == 0) { Measurement("0") } else { Measurement("${nr}px") }
fun px(nr: Double) = Measurement("${nr}px")
fun em(nr: Int) = Measurement("${nr}em")
fun em(nr: Double) = Measurement("${nr}em")
fun perc(nr: Int) = Measurement("${nr}%")
fun perc(nr: Double) = Measurement("${nr}%")
fun pc(nr: Int) = Measurement("${nr}pc")
fun pc(nr: Double) = Measurement("${nr}pc")
fun cm(nr: Int) = Measurement("${nr}cm")
fun cm(nr: Double) = Measurement("${nr}cm")
fun px(nr: Double) = nr.px
fun em(nr: Int) = nr.em
fun em(nr: Double) = nr.em
fun perc(nr: Int) = nr.perc
fun perc(nr: Double) = nr.perc
fun pc(nr: Int) = nr.pc
fun pc(nr: Double) = nr.pc
fun cm(nr: Int) = nr.cm
fun cm(nr: Double) = nr.cm
}
}
val Int.px: Measurement
get() = Measurement("${this}${if (this == 0) { "" } else { "px"}}")
val Int.em: Measurement
get() = Measurement("${this}${if (this == 0) { "" } else { "em"}}")
val Int.perc: Measurement
get() = Measurement("${this}%")
val Int.pc: Measurement
get() = Measurement("${this}pc")
val Int.cm: Measurement
get() = Measurement("${this}cm")
fun Int.px(): Measurement = Measurement.px(this)
val Double.px: Measurement
get() = Measurement("${this}px")
val Double.em: Measurement
get() = Measurement("${this}em")
val Double.perc: Measurement
get() = Measurement("${this}%")
val Double.pc: Measurement
get() = Measurement("${this}pc")
val Double.cm: Measurement
get() = Measurement("${this}cm")
fun Double.px(): Measurement = Measurement.px(this)
fun Int.em(): Measurement = Measurement.em(this)
fun Double.em(): Measurement = Measurement.em(this)
fun Int.perc(): Measurement = Measurement.perc(this)
fun Double.perc(): Measurement = Measurement.perc(this)
fun Int.pc(): Measurement = Measurement.pc(this)
fun Double.pc(): Measurement = Measurement.pc(this)
fun Int.cm(): Measurement = Measurement.cm(this)
fun Double.cm(): Measurement = Measurement.cm(this)
open class LineHeight(value: String) : CssProperty(value) {
companion object {

View File

@@ -0,0 +1,107 @@
package nl.astraeus.css.properties
import kotlin.math.max
import kotlin.math.min
class RgbaColor(
val red: Int,
val green: Int,
val blue: Int,
val alpha: Double = 1.0
): Color("rgba($red,$green,$blue,$alpha)") {
fun toHsla(): HslaColor = HslaColor.fromRgba(this)
companion object {
private fun findValues(value: String, expectedNumber: Int): List<String> {
check(value.contains('(') && value.contains(')'))
val parts = value.split('(')[1].split(')')[0].split(',')
check(parts.size == expectedNumber)
return parts
}
fun fromString(value: String): RgbaColor = when {
value.trim().startsWith("#") -> {
fromHex(value.substringAfterLast('#'))
}
value.trim().startsWith("hsla") -> {
val values = findValues(value, 4)
fromHsla(
values[0].toInt(),
values[1].toInt(),
values[2].toInt(),
values[3].toDouble()
)
}
value.trim().startsWith("hsl") -> {
val values = findValues(value, 3)
fromHsl(
values[0].toInt(),
values[1].toInt(),
values[2].toInt()
)
}
value.trim().startsWith("rgba") -> {
val values = findValues(value, 4)
RgbaColor(
values[0].toInt(),
values[1].toInt(),
values[2].toInt(),
values[3].toDouble()
)
}
value.trim().startsWith("rgb") -> {
val values = findValues(value, 3)
RgbaColor(
values[0].toInt(),
values[1].toInt(),
values[2].toInt()
)
}
else -> {
throw IllegalArgumentException("Unable to parse $value as color")
}
}
fun fromHex(value: String): RgbaColor {
TODO("Implement parsing hex to rgba")
}
fun fromHsla(hsla: HslaColor): RgbaColor = fromHsla(
hsla.hue,
hsla.saturation,
hsla.lightness,
hsla.alpha
)
fun fromHsl(
hue: Int,
saturation: Int,
lightness: Int
): RgbaColor {
return fromHsla(hue, saturation, lightness, 1.0)
}
fun fromHsla(
hue: Int,
saturation: Int,
lightness: Int,
alpha: Double
): RgbaColor {
val h = hue
val s = saturation / 100.0
val l = lightness / 100.0
val a = s * min(l, 1 - l)
fun f(n: Int): Int {
val k: Int = (n + h / 30) % 12
return (255 * (l - a * max(min(k - 3, min(9 - k, 1)), -1))).toInt()
}
return RgbaColor(f(0), f(8), f(4), alpha)
}
}
}

View File

@@ -0,0 +1,71 @@
package nl.astraeus.css
import nl.astraeus.css.properties.*
import kotlin.test.Test
class TestColor {
@Test
fun testBuilder() {
val css = style {
val baseColor = HslaColor(20, 50, 50)
val baseColorRgb = RgbaColor.fromHsla(baseColor)
println("BaseColor: ${baseColor.value} - ${baseColorRgb.value}")
val darkerColor = baseColor.darken(10)
val darkerColorRgb = RgbaColor.fromHsla(darkerColor)
println("DarkerColor: ${darkerColor.value} - ${darkerColorRgb.value}")
val saturizedColor = baseColor.saturize(10)
val saturizedColorRgb = RgbaColor.fromHsla(saturizedColor)
println("SaturizedColor: ${saturizedColor.value} - ${saturizedColorRgb.value}")
val redColor = RgbaColor(0,255,0,1.0)
val redColorHsla = redColor.toHsla()
val shiftedColor = redColorHsla.adjustHue(120)
val shiftedColorRgb = shiftedColor.toRgba()
println("RedColor: ${redColor.value} - ${redColorHsla.value}")
println("ShiftedColor: ${shiftedColor.value} - ${shiftedColorRgb.value}")
select(".test") {
top(10.px)
left(4.em)
backgroundColor(
RgbaColor.fromHsla(baseColor.darken(10))
)
animationIterationMode(
Count.auto,
Count.auto,
Count.auto,
Count.auto,
Count.auto
)
child("li") {
color(Color.hsl(200, 50, 50))
}
select("> a") {
color(Color.hsl(200, 50, 50))
}
}
}
println(css.generateCss())
val css2 = style {
cls("button") {
fontSize(12.px)
color(Color.hsl(200, 50, 50))
}
}
println(css2.generateCss())
}
}

View File

@@ -1,16 +1,20 @@
package nl.astraeus.css
object TestCssBuilder {
/*
@Test
fun testBuilder() {
val css = CssBuilder()
import nl.astraeus.css.properties.Color.Companion.hsl
import nl.astraeus.css.properties.Color.Companion.rgba
import nl.astraeus.css.properties.Count
import nl.astraeus.css.properties.em
import nl.astraeus.css.properties.px
css.style {
object TestCssBuilder {
//@Test
fun testBuilder() {
val css = css {
select(".test") {
top(10.px())
left(4.em())
top(10.px)
left(4.em)
backgroundColor(rgba(255, 255, 255, 0.75))
animationIterationMode(
Count.auto,
@@ -20,6 +24,9 @@ object TestCssBuilder {
Count.auto
)
child("li") {
color(hsl(200,50,50))
}
select("> a") {
color(hsl(200, 50, 50))
@@ -28,6 +35,17 @@ object TestCssBuilder {
}
println(css)
}*/
val css2 = css {
cls("button") {
fontSize(12.px)
color(hsl(200, 50, 50))
}
}
println(css2)
}
}