Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -266,17 +266,17 @@ class ArithmeticExpressionScope private constructor() {
operator fun Exp.Int.not() = Exp.Boolean { "!$this" }
operator fun Exp.Boolean.not() = Exp.Boolean { "!$this" }

@Suppress("DANGEROUS_CHARACTERS")
infix fun Int.`|`(other: Exp.Int) = Exp.Int { "$this | $other" }

@Suppress("DANGEROUS_CHARACTERS")
infix fun Exp.Int.`|`(other: Int) = Exp.Int { "$this | $other" }

@Suppress("DANGEROUS_CHARACTERS")
infix fun Exp.Int.`|`(other: Exp.Int) = Exp.Int { "$this | $other" }

@Suppress("DANGEROUS_CHARACTERS")
infix fun Exp.Boolean.`||`(other: Exp.Boolean) = Exp.Boolean { "$this || $other" }
// @Suppress("DANGEROUS_CHARACTERS")
// infix fun Int.`|`(other: Exp.Int) = Exp.Int { "$this | $other" }
//
// @Suppress("DANGEROUS_CHARACTERS")
// infix fun Exp.Int.`|`(other: Int) = Exp.Int { "$this | $other" }
//
// @Suppress("DANGEROUS_CHARACTERS")
// infix fun Exp.Int.`|`(other: Exp.Int) = Exp.Int { "$this | $other" }
//
// @Suppress("DANGEROUS_CHARACTERS")
// infix fun Exp.Boolean.`||`(other: Exp.Boolean) = Exp.Boolean { "$this || $other" }

infix fun Int.`&`(other: Exp.Int) = Exp.Int { "$this & $other" }
infix fun Exp.Int.`&`(other: Int) = Exp.Int { "$this & $other" }
Expand Down
3 changes: 2 additions & 1 deletion extensions/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
id("kotlin-jvm-lib")
kotlin("jvm")
id("org.jetbrains.compose") version "1.6.2"
}

dependencies {
Expand Down
21 changes: 21 additions & 0 deletions previews/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
plugins {
kotlin("jvm")
id("org.jetbrains.compose") version "1.6.2"
}

dependencies {
api(project(":core"))

implementation(compose.desktop.currentOs)

testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.3")
}

kotlin {
compilerOptions.freeCompilerArgs.add("-Xcontext-receivers")
}

tasks.named<Test>("test") {
useJUnitPlatform()
}
63 changes: 63 additions & 0 deletions previews/src/main/kotlin/splitties/wff/previews/TagTree.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package splitties.wff.previews

import kotlinx.html.Tag
import splitties.wff.SCENE
import splitties.wff.WATCHFACE
import splitties.wff.XMLTag
import splitties.wff.attr.AttrRef
import splitties.wff.clock.TIMETEXT
import splitties.wff.common.attributes.ArithmeticExpression

class TagTree {
lateinit var watchface: WATCHFACE

val childMap = mutableMapOf<Tag, MutableList<Tag>>()
val tagContent = mutableMapOf<Tag, String>()
val stack = mutableListOf<Tag>()

fun push(tag: Tag) {
if (tag is WATCHFACE) {
watchface = tag
} else {
childMap.getOrPut(stack.last()) { mutableListOf() }.add(tag)
}

stack.add(tag)
}

fun pop(tag: Tag) {
val removed = stack.removeLast()
check(removed == tag)
}

fun content(content: CharSequence) {
tagContent[stack.last()] = content.toString()
}

val WATCHFACE.scene: SCENE
get() = childMap.getValue(this).find { it is SCENE } as SCENE

val Tag.children: List<Tag>
get() = childMap[this].orEmpty()

val Tag.content: String?
get() = tagContent[this]
}

val TIMETEXT.format: String
get() = this.attributes.getValue("format")

val TIMETEXT.align: String
get() = this.attributes.getValue("format")

context(XMLTag)
val AttrRef<ArithmeticExpression.Int>.value: Int
get() {
val value = attributes.getValue(this.name).toString().toIntOrNull()

if (value == null) {
println("Int value: $this ${this.name}")
}

return value ?: 0
}
64 changes: 64 additions & 0 deletions previews/src/main/kotlin/splitties/wff/previews/TagTreeConsumer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package splitties.wff.previews

import kotlinx.html.Entities
import kotlinx.html.Tag
import kotlinx.html.TagConsumer
import kotlinx.html.Unsafe
import kotlinx.html.org.w3c.dom.events.Event

class TagTreeConsumer: TagConsumer<TagTree> {
val tree = TagTree()

override fun finalize(): TagTree {
return tree.also {
println(it)
}
}

override fun onTagAttributeChange(tag: Tag, attribute: String, value: String?) {
println("onTagAttributeChange: $tag $attribute=$value")
}

override fun onTagComment(content: CharSequence) {
println("onTagComment: $content")
}

override fun onTagContent(content: CharSequence) {
println("onTagContent: $content")

tree.content(content)
}

override fun onTagContentEntity(entity: Entities) {
println("onTagContentEntity: $entity")
}

override fun onTagContentUnsafe(block: Unsafe.() -> Unit) {
println("onTagContentUnsafe")
}

override fun onTagStart(tag: Tag) {
println("onTagStart: $tag ${tag.attributes.toMap()}")

tree.push(tag)
}

override fun onTagEvent(tag: Tag, event: String, value: (Event) -> Unit) {
println("onTagEvent: $tag")
}

override fun onTagEnd(tag: Tag) {
println("onTagEnd: $tag")

tree.pop(tag)
}
}

abstract class WffNode() {
abstract val name: String

}

class Unknown(override val name: String): WffNode() {

}
130 changes: 130 additions & 0 deletions previews/src/main/kotlin/splitties/wff/previews/WffPreview.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package splitties.wff.previews

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFontFamilyResolver
import androidx.compose.ui.text.TextMeasurer
import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import kotlinx.html.Tag
import splitties.wff.Alignment
import splitties.wff.GROUP
import splitties.wff.SCENE
import splitties.wff.WATCHFACE
import splitties.wff.WatchFaceDsl
import splitties.wff.clock.DIGITALCLOCK
import splitties.wff.clock.TIMETEXT
import splitties.wff.group.part.text.PARTTEXT
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

@Composable
fun WffPreview(watchface: WatchFaceDsl<TagTree>.() -> TagTree) {
val tagTree = with(WatchFaceDsl(TagTreeConsumer())) {
watchface()
}

val dp = with(LocalDensity.current) {
(450.0f).toDp()
}
with(DrawResources(LocalFontFamilyResolver.current, LocalDensity.current)) {
Canvas(modifier = Modifier.size(dp)) {
tagTree.draw()
}
}
}

context(DrawScope, DrawResources)
private fun TagTree.draw() {
watchface.drawWatchface()
}

context(DrawScope, TagTree, DrawResources)
private fun WATCHFACE.drawWatchface() {
scene.draw()
}

context(DrawScope, TagTree, DrawResources)
private fun Tag.draw() {
when (this) {
is SCENE -> drawScene()
is DIGITALCLOCK -> drawDigitalClock()
is TIMETEXT -> drawTimeText()
is GROUP -> drawGroup()
is PARTTEXT -> drawPartText()
else -> println("Can't draw unknown: $this")
}
}

context(DrawScope, TagTree, DrawResources)
private fun SCENE.drawScene() {
children.forEach {
it.draw()
}
}

context(DrawScope, TagTree, DrawResources)
private fun GROUP.drawGroup() {
children.forEach {
it.draw()
}
}

context(DrawScope, TagTree, DrawResources)
private fun DIGITALCLOCK.drawDigitalClock() {
children.forEach {
it.draw()
}
}

context(DrawScope, TagTree, DrawResources)
private fun TIMETEXT.drawTimeText() {
val text = formatTime(this.format)

val topLeft = Offset(attrs.x.value.toFloat(), attrs.y.value.toFloat())
val size = Size(attrs.width.value.toFloat(), attrs.height.value.toFloat())
val align = Alignment.valueOf(attributes["align"] ?: "START")

drawText(textMeasurer = textMeasurer, text = text, topLeft = topLeft, size = size, align = align)
}

context(DrawScope, TagTree, DrawResources)
private fun PARTTEXT.drawPartText() {
val text = content ?: "MISSING!"

val topLeft = Offset(attrs.x.value.toFloat(), attrs.y.value.toFloat())
val size = Size(attrs.width.value.toFloat(), attrs.height.value.toFloat())
val align = Alignment.valueOf(attributes["align"] ?: "START")

drawText(textMeasurer = textMeasurer, text = text, topLeft = topLeft, size = size, align = align)
}

context(DrawScope, TagTree, DrawResources)
private fun drawText(text: String, textMeasurer: TextMeasurer, topLeft: Offset, size: Size, align: Alignment) {
val result = textMeasurer.measure(text, maxLines = 1, constraints = Constraints(maxWidth = size.width.toInt(), maxHeight = size.width.toInt()))

drawText(result, topLeft = topLeft)
}

class DrawResources(resolver: FontFamily.Resolver, density: Density) {
val time = LocalDateTime.now()
val textMeasurer = TextMeasurer(resolver, density, LayoutDirection.Ltr)

init {
println("Density: ${density.density}")
}

fun formatTime(format: String): String {
val formatter = DateTimeFormatter.ofPattern(format)
return formatter.format(time)
}
}
14 changes: 14 additions & 0 deletions sample/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
plugins {
kotlin("jvm")
id("org.jetbrains.compose") version "1.6.2"
}

kotlin {
compilerOptions.freeCompilerArgs.add("-Xcontext-receivers")
}

dependencies {
api(project(":core"))
api(project(":previews"))
implementation(compose.desktop.currentOs)
}
Loading