Files
vst-chip/src/jsMain/kotlin/nl/astraeus/vst/chip/view/MainView.kt
2024-06-27 12:32:17 +02:00

280 lines
7.5 KiB
Kotlin

package nl.astraeus.vst.chip.view
import kotlinx.browser.window
import kotlinx.html.*
import kotlinx.html.js.onChangeFunction
import kotlinx.html.js.onClickFunction
import kotlinx.html.js.onInputFunction
import nl.astraeus.css.properties.*
import nl.astraeus.css.style.cls
import nl.astraeus.komp.HtmlBuilder
import nl.astraeus.komp.Komponent
import nl.astraeus.vst.chip.audio.VstChipWorklet
import nl.astraeus.vst.chip.midi.Midi
import nl.astraeus.vst.ui.components.ExpKnobComponent
import nl.astraeus.vst.ui.css.Css
import nl.astraeus.vst.ui.css.Css.defineCss
import nl.astraeus.vst.ui.css.Css.noTextSelect
import nl.astraeus.vst.ui.css.CssName
import nl.astraeus.vst.ui.css.hover
import org.khronos.webgl.Uint8Array
import org.w3c.dom.HTMLInputElement
import org.w3c.dom.HTMLSelectElement
object MainView : Komponent(), CssName {
private var messages: MutableList<String> = ArrayList()
private var started = false
init {
css()
}
fun addMessage(message: String) {
messages.add(message)
while (messages.size > 10) {
messages.removeAt(0)
}
requestUpdate()
}
override fun HtmlBuilder.render() {
div(MainDivCss.name) {
if (!started) {
div(StartSplashCss.name) {
div(StartBoxCss.name) {
div(StartButtonCss.name) {
+"START"
onClickFunction = {
started = true
VstChipWorklet.create {
requestUpdate()
}
}
}
}
}
}
h1 {
+"VST Chip"
}
div {
span {
+"Midi input: "
select {
option {
+"None"
value = "none"
}
for (mi in Midi.inputs) {
option {
+mi.name
value = mi.id
}
}
onChangeFunction = { event ->
val target = event.target as HTMLSelectElement
if (target.value == "none") {
Midi.setInput(null)
} else {
val selected = Midi.inputs.find { it.id == target.value }
if (selected != null) {
Midi.setInput(selected)
} else if (target.value == "midi-broadcast") {
//
}
}
}
}
}
span {
+"channel:"
input {
type = InputType.number
value = Midi.inputChannel.toString()
onInputFunction = { event ->
val target = event.target as HTMLInputElement
Midi.inputChannel = target.value.toInt()
println("onInput channel: ${Midi.inputChannel}")
VstChipWorklet.postMessage("set_channel\n${Midi.inputChannel}")
}
}
}
}
div {
span {
+"Midi output: "
select {
option {
+"None"
value = "none"
}
for (mi in Midi.outputs) {
option {
+mi.name
value = mi.id
}
}
onChangeFunction = { event ->
val target = event.target as HTMLSelectElement
if (target.value == "none") {
Midi.setOutput(null)
} else {
val selected = Midi.outputs.find { it.id == target.value }
if (selected != null) {
Midi.setOutput(selected)
}
}
}
}
}
span {
+"channel:"
input {
type = InputType.number
value = Midi.outputChannel.toString()
onInputFunction = { event ->
val target = event.target as HTMLInputElement
Midi.outputChannel = target.value.toInt()
}
}
}
}
div(ButtonCss.name) {
+"Send note on to output"
onClickFunction = {
val data = Uint8Array(
arrayOf(
0x90.toByte(),
0x3c.toByte(),
0x70.toByte()
)
)
Midi.send(data, window.performance.now() + 1000)
Midi.send(data, window.performance.now() + 2000)
}
}
div(ButtonCss.name) {
+"Send note off to output"
onClickFunction = {
val data = Uint8Array(
arrayOf(
0x90.toByte(),
0x3c.toByte(),
0x0.toByte(),
)
)
Midi.send(data)
}
}
div {
include(
ExpKnobComponent(
)
)
}
}
}
object MainDivCss : CssName
object ActiveCss : CssName
object ButtonCss : CssName
object NoteBarCss : CssName
object StartSplashCss : CssName
object StartBoxCss : CssName
object StartButtonCss : CssName
private fun css() {
defineCss {
select("*") {
select("*:before") {
select("*:after") {
boxSizing(BoxSizing.borderBox)
}
}
}
select("html", "body") {
margin(0.px)
padding(0.px)
height(100.prc)
}
select("html", "body") {
backgroundColor(Css.currentStyle.mainBackgroundColor)
color(Css.currentStyle.mainFontColor)
fontFamily("JetbrainsMono, monospace")
fontSize(14.px)
fontWeight(FontWeight.bold)
//transition()
noTextSelect()
}
select(cls(ButtonCss)) {
margin(1.rem)
padding(1.rem)
backgroundColor(Css.currentStyle.buttonBackgroundColor)
borderColor(Css.currentStyle.buttonBorderColor)
borderWidth(Css.currentStyle.buttonBorderWidth)
color(Css.currentStyle.mainFontColor)
hover {
backgroundColor(Css.currentStyle.buttonBackgroundColor.hover())
}
}
select(cls(ActiveCss)) {
//backgroundColor(Css.currentStyle.selectedBackgroundColor)
}
select(cls(NoteBarCss)) {
minHeight(4.rem)
}
select(cls(MainDivCss)) {
margin(1.rem)
}
select("select") {
plain("appearance", "none")
border("0")
outline("0")
width(20.rem)
padding(0.5.rem, 2.rem, 0.5.rem, 0.5.rem)
backgroundImage("url('https://upload.wikimedia.org/wikipedia/commons/9/9d/Caret_down_font_awesome_whitevariation.svg')")
background("right 0.8em center/1.4em")
backgroundColor(Css.currentStyle.inputBackgroundColor)
//color(Css.currentStyle.entryFontColor)
borderRadius(0.25.em)
}
select(cls(StartSplashCss)) {
position(Position.fixed)
left(0.px)
top(0.px)
width(100.vw)
height(100.vh)
zIndex(100)
backgroundColor(hsla(32, 0, 50, 0.6))
select(cls(StartBoxCss)) {
position(Position.relative)
left(25.vw)
top(25.vh)
width(50.vw)
height(50.vh)
backgroundColor(hsla(0, 0, 50, 0.25))
select(cls(StartButtonCss)) {
position(Position.absolute)
left(50.prc)
top(50.prc)
transform(Transform("translate(-50%, -50%)"))
padding(1.rem)
backgroundColor(Css.currentStyle.buttonBackgroundColor)
cursor("pointer")
}
}
}
}
}
}