Initial commit

This commit is contained in:
2024-06-16 20:40:05 +02:00
commit 68b7ffffa8
42 changed files with 1729 additions and 0 deletions

View File

@@ -0,0 +1,184 @@
package nl.astraeus.vst.chip.view
import daw.style.Css
import daw.style.Css.defineCss
import daw.style.Css.noTextSelect
import daw.style.CssId
import daw.style.CssName
import daw.style.hover
import kotlinx.html.FlowContent
import kotlinx.html.a
import kotlinx.html.classes
import kotlinx.html.div
import kotlinx.html.h1
import kotlinx.html.hr
import kotlinx.html.js.onClickFunction
import kotlinx.html.js.onMouseDownFunction
import kotlinx.html.js.onMouseUpFunction
import kotlinx.html.span
import nl.astraeus.css.properties.BoxSizing
import nl.astraeus.css.properties.FontWeight
import nl.astraeus.css.properties.prc
import nl.astraeus.css.properties.px
import nl.astraeus.css.properties.rem
import nl.astraeus.css.style.cls
import nl.astraeus.komp.HtmlBuilder
import nl.astraeus.komp.Komponent
import nl.astraeus.vst.Note
import nl.astraeus.vst.chip.audio.VstChipWorklet
import nl.astraeus.vst.chip.channel.Broadcaster
import org.khronos.webgl.Int32Array
object MainView : Komponent() {
private var messages: MutableList<String> = ArrayList()
init {
MainViewCss
}
fun addMessage(message: String) {
messages.add(message)
while (messages.size > 10) {
messages.removeAt(0)
}
requestUpdate()
}
override fun HtmlBuilder.render() {
div {
h1 {
+"VST Chip"
}
div {
+"Hello, World!"
}
div {
if (VstChipWorklet.created) {
+"Worklet created"
} else {
a {
href = "#"
+"Create worklet"
onClickFunction = {
VstChipWorklet.create {
requestUpdate()
}
}
}
}
}
div {
a {
href = "#"
+"Send broadcast test message"
onClickFunction = {
Broadcaster.send("Test message")
}
}
}
div {
a {
href = "#"
+"Note on"
onClickFunction = {
VstChipWorklet.postMessage("test_on")
}
}
a {
href = "#"
+"Note off"
onClickFunction = {
VstChipWorklet.postMessage("test_off")
}
}
}
hr {}
repeat(9) {
div(classes = MainViewCss.NoteBarCss.name) {
for (index in it*12+12..it*12+23) {
notePlayer(Note.entries[index])
}
}
}
hr {}
for (message in messages) {
div {
+message
}
}
}
}
private fun FlowContent.notePlayer(note: Note) {
span {
a(classes = MainViewCss.ButtonCss.name) {
href = "#"
+note.sharp
onMouseDownFunction = {
VstChipWorklet.postMessage(Int32Array(arrayOf(0x90, note.ordinal, 32)))
}
onMouseUpFunction = {
VstChipWorklet.postMessage(Int32Array(arrayOf(0x90, note.ordinal, 0)))
}
/*
onMouseOutFunction = {
VstChipWorklet.postMessage(Int32Array(arrayOf(0x90, note.ordinal, 0)))
}
*/
}
}
}
object MainViewCss : CssId("main") {
object ActiveCss : CssName()
object ButtonCss : CssName()
object NoteBarCss : CssName()
init {
defineCss {
select("*") {
select("*:before") {
select("*:after") {
boxSizing(BoxSizing.borderBox)
}
}
}
select("html", "body") {
margin(0.px)
padding(0.px)
height(100.prc)
color(Css.currentStyle.mainFontColor)
backgroundColor(Css.currentStyle.mainBackgroundColor)
fontFamily("JetbrainsMono, monospace")
fontSize(14.px)
fontWeight(FontWeight.bold)
//transition()
noTextSelect()
}
select(cls(ButtonCss)) {
margin(1.rem)
padding(1.rem)
backgroundColor(Css.currentStyle.buttonBackgroundColor)
hover {
backgroundColor(Css.currentStyle.buttonBackgroundColor.hover())
}
}
select(cls(ActiveCss)) {
backgroundColor(Css.currentStyle.selectedBackgroundColor)
}
select(cls(NoteBarCss)) {
minHeight(4.rem)
}
}
}
}
}

View File

@@ -0,0 +1,137 @@
package daw.style
import kotlinx.browser.document
import nl.astraeus.css.properties.Color
import nl.astraeus.css.properties.UserSelect
import nl.astraeus.css.properties.hsl
import nl.astraeus.css.properties.hsla
import nl.astraeus.css.style
import nl.astraeus.css.style.ConditionalStyle
import nl.astraeus.css.style.Style
class StyleDefinition(
val mainFontColorNumber: Int = 32,
val mainFontColor: Color = hsla(mainFontColorNumber, 70, 55, 1.0),
val mainBackgroundColor: Color,
val selectedBackgroundColor: Color = hsl((Css.mainFontColorNumber + 180) % 360, 40, 30),
val mainBorderColor: Color = hsla((Css.mainFontColorNumber + 270) % 360, 0, 20, 0.5),
val headerFontColor: Color = hsl(Css.mainFontColorNumber, 50, 95),
val entryFontColor: Color = hsl(Css.mainFontColorNumber, 70, 55),
val successColor: Color = hsl(120, 70, 55),
val highlightFontColor : Color = hsl(Css.mainFontColorNumber, 70, 65),
val menuFontColor : Color = hsl(Css.mainFontColorNumber, 50, 100),
val menuBackgroundColor : Color = hsl(Css.mainFontColorNumber, 50, 16),
val backgroundComponentColor : Color = hsl(0, 0, 16),
val inputBackgroundColor : Color = hsl(0, 0, 20),
val inputBorderColor : Color = hsl(Css.mainFontColorNumber, 50, 50),
val buttonFontColor : Color = hsl(Css.mainFontColorNumber, 50, 95),
val buttonBackgroundColor : Color = hsl(Css.mainFontColorNumber, 70, 55),
val tabColor: Color = mainFontColor.darken(20),
val tabSelectedColor: Color = mainFontColor.lighten(10),
val tabHoverColor: Color = tabSelectedColor.lighten(20),
)
object NoTextSelectCls : CssName("no-text-select")
object SelectedCls : CssName("selected")
object ActiveCls : CssName("active")
fun Color.hover(): Color = if (Css.currentStyle == Css.darkStyle) {
this.lighten(15)
} else {
this.darken(15)
}
object Css {
var minified = false
var mainFontColorNumber = 32
var dynamicStyles = mutableMapOf<CssId, ConditionalStyle.() -> Unit>()
fun CssId.defineCss(conditionalStyle: ConditionalStyle.() -> Unit) {
check(!dynamicStyles.containsKey(this)) {
"CssId with name ${this.name} already defined!"
}
updateCss(conditionalStyle)
}
private fun CssId.updateCss(conditionalStyle: ConditionalStyle.() -> Unit) {
val elementId = this.description()
var dynamicStyleElement = document.getElementById(elementId)
dynamicStyles[this] = conditionalStyle
if (dynamicStyleElement == null) {
dynamicStyleElement = document.createElement("style")
dynamicStyleElement.id = elementId
document.head?.append(dynamicStyleElement)
}
val css = style(conditionalStyle)
dynamicStyleElement.innerHTML = css.generateCss(minified = false)
}
val darkStyle = StyleDefinition(
mainFontColorNumber = mainFontColorNumber,
mainBackgroundColor = hsl(0, 0, 10)
)
val lightStyle = StyleDefinition(
mainFontColorNumber = (mainFontColorNumber + 120) % 360,
mainBackgroundColor = hsl(0, 0, 98),
mainBorderColor = hsla((Css.mainFontColorNumber + 270) % 360, 0, 20, 0.15),
headerFontColor = hsl(mainFontColorNumber, 50, 5),
backgroundComponentColor = hsl(0, 0, 84),
)
var currentStyle: StyleDefinition = darkStyle
fun updateStyle() {
for ((cssId, dynStyle) in dynamicStyles) {
cssId.apply {
updateCss(dynStyle)
}
}
}
fun switchLayout() {
currentStyle = if (currentStyle == darkStyle) {
lightStyle
} else {
darkStyle
}
updateStyle()
}
fun Style.transition() {
transition("all 0.5s ease")
}
fun Style.noTextSelect() {
plain("-webkit-touch-callout", "none")
plain("-webkit-user-select", "none")
plain("-moz-user-select", "none")
plain("-ms-user-select", "none")
userSelect(UserSelect.none)
select("::selection") {
background("none")
}
}
object GenericCss : CssId("generic") {
init {
fun generateStyle(): String {
val css = style {
}
return css.generateCss(minified = minified)
}
}
}
}

View File

@@ -0,0 +1,65 @@
package daw.style
import nl.astraeus.css.style.DescriptionProvider
import nl.astraeus.css.style.cls
private val CAPITAL_LETTER = Regex("[A-Z]")
fun String.hyphenize(): String =
replace(CAPITAL_LETTER) {
"-${it.value.lowercase()}"
}
private val shortId = false
private var nextCssId = 1
private fun nextShortId(): String {
var id = nextCssId++
val result = StringBuilder()
while(id > 0) {
val ch = ((id % 26) + 'a'.code).toChar()
result.append(ch)
id /= 26
}
return result.toString()
}
open class CssName(name: String? = null) : DescriptionProvider {
val name: String = if (shortId) {
nextShortId()
} else if (name != null) {
"daw-$name"
} else {
"daw${this::class.simpleName?.hyphenize() ?: this::class}"
}
override fun description() = name
}
fun CssName.cls() : DescriptionProvider = cls(this)
open class CssId(name: String) : DescriptionProvider {
val name: String = if (shortId) {
nextShortId()
} else {
"daw-$name-css"
}
override fun description() = name
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is CssId) return false
if (name != other.name) return false
return true
}
override fun hashCode(): Int {
return name.hashCode()
}
}