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

288 lines
7.6 KiB
Kotlin

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.browser.window
import kotlinx.html.InputType
import kotlinx.html.div
import kotlinx.html.h1
import kotlinx.html.input
import kotlinx.html.js.onChangeFunction
import kotlinx.html.js.onClickFunction
import kotlinx.html.option
import kotlinx.html.select
import kotlinx.html.span
import nl.astraeus.css.properties.BoxSizing
import nl.astraeus.css.properties.FontWeight
import nl.astraeus.css.properties.Position
import nl.astraeus.css.properties.Transform
import nl.astraeus.css.properties.em
import nl.astraeus.css.properties.hsla
import nl.astraeus.css.properties.prc
import nl.astraeus.css.properties.px
import nl.astraeus.css.properties.rem
import nl.astraeus.css.properties.vh
import nl.astraeus.css.properties.vw
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 org.khronos.webgl.Uint8Array
import org.w3c.dom.HTMLInputElement
import org.w3c.dom.HTMLSelectElement
object MainView : Komponent() {
private var messages: MutableList<String> = ArrayList()
private var started = false
init {
MainViewCss
}
fun addMessage(message: String) {
messages.add(message)
while (messages.size > 10) {
messages.removeAt(0)
}
requestUpdate()
}
override fun HtmlBuilder.render() {
div(MainViewCss.MainDivCss.name) {
if (!started) {
div(MainViewCss.StartSplashCss.name) {
div(MainViewCss.StartBoxCss.name) {
div(MainViewCss.StartButtonCss.name) {
+"START"
onClickFunction = {
started = true
VstChipWorklet.create {
requestUpdate()
}
}
}
}
}
}
h1 {
+"VST Chip"
}
div {
span {
+"Midi input: "
select {
option {
+"None"
value = ""
}
option {
+"Midi over Broadcast"
value = "midi-broadcast"
}
for (mi in Midi.inputs) {
option {
+mi.name
value = mi.id
}
}
onChangeFunction = { event ->
val target = event.target as HTMLSelectElement
if (target.value == "") {
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()
onChangeFunction = { event ->
val target = event.target as HTMLInputElement
Midi.inputChannel = target.value.toInt()
}
}
}
}
div {
span {
+"Midi output: "
select {
option {
+"None"
value = ""
}
option {
+"Midi over Broadcast"
value = "midi-broadcast"
}
for (mi in Midi.outputs) {
option {
+mi.name
value = mi.id
}
}
onChangeFunction = { event ->
val target = event.target as HTMLSelectElement
if (target.value == "") {
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()
onChangeFunction = { event ->
val target = event.target as HTMLInputElement
Midi.outputChannel = target.value.toInt()
}
}
}
}
div {
+"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 {
+"Send note off to output"
onClickFunction = {
val data = Uint8Array(
arrayOf(
0x90.toByte(),
0x3c.toByte(),
0x0.toByte(),
)
)
Midi.send(data)
}
}
}
}
object MainViewCss : CssId("main") {
object MainDivCss : CssName()
object ActiveCss : CssName()
object ButtonCss : CssName()
object NoteBarCss : CssName()
object StartSplashCss : CssName()
object StartBoxCss : CssName()
object StartButtonCss : CssName()
init {
defineCss {
select("*") {
select("*:before") {
select("*:after") {
boxSizing(BoxSizing.borderBox)
}
}
}
select("html", "body") {
margin(0.px)
padding(0.px)
height(100.prc)
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)
}
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")
}
}
}
}
}
}
}