package ocelot.desktop.ui.widget import ocelot.desktop.OcelotDesktop import ocelot.desktop.audio.{ClickSoundSourceFactory, SoundSource} import ocelot.desktop.geometry.Padding2D import ocelot.desktop.ui.layout.LinearLayout import ocelot.desktop.ui.widget.ChangeSimulationSpeedDialog.validateIntervalUs import ocelot.desktop.ui.widget.modal.ModalDialog import ocelot.desktop.util.Orientation import scala.concurrent.duration.{Duration, DurationLong} class ChangeSimulationSpeedDialog extends ModalDialog { private var tickInterval: Option[Duration] = Some(OcelotDesktop.ticker.tickInterval) private def confirm(): Unit = { if (tickInterval.isDefined) { OcelotDesktop.ticker.tickInterval = tickInterval.get OcelotDesktop.pushToTickerIntervalHistory(tickInterval.get) } close() } children :+= new PaddingBox( new Widget { override val layout = new LinearLayout(this, orientation = Orientation.Vertical) children :+= new PaddingBox(new Label("Change simulation speed"), Padding2D(bottom = 16)) private var inputTPS: TextInput = _ private var inputMSPT: TextInput = _ private def formatMSPT(interval: Duration): String = (interval.toMicros / 1000f).toString private def formatTPS(interval: Duration): String = (1_000_000f / interval.toMicros).toString inputMSPT = new TextInput(formatMSPT(OcelotDesktop.ticker.tickInterval)) { focus() private def parseInput(text: String): Option[Duration] = { try { validateIntervalUs((text.toFloat * 1000).toLong) } catch { case _: NumberFormatException => None } } override def onInput(text: String): Unit = { tickInterval = parseInput(text).map { interval => val tps = formatTPS(interval) if (inputTPS.text != tps) inputTPS.text = tps interval } } override def validator(text: String): Boolean = parseInput(text).isDefined override def onConfirm(): Unit = confirm() } inputTPS = new TextInput(formatTPS(OcelotDesktop.ticker.tickInterval)) { private def parseInput(text: String): Option[Duration] = { try { validateIntervalUs((1_000_000 / text.toFloat).toLong) } catch { case _: NumberFormatException => None } } override def onInput(text: String): Unit = { tickInterval = parseInput(text).map { interval => val mspt = formatMSPT(interval) if (inputMSPT.text != mspt) inputMSPT.text = mspt interval } } override def validator(text: String): Boolean = parseInput(text).isDefined override def onConfirm(): Unit = confirm() } children :+= new Label("Milliseconds per tick:") children :+= new PaddingBox(inputMSPT, Padding2D(bottom = 8)) children :+= new Label("Ticks per second:") children :+= new PaddingBox(inputTPS, Padding2D(bottom = 8)) children :+= new Widget { children :+= new Filler children :+= new PaddingBox( new Button { override def text: String = "Cancel" override protected def clickSoundSource: ClickSoundSourceFactory = SoundSource.InterfaceClickLow override def onClick(): Unit = close() }, Padding2D(right = 8), ) children :+= new Button { override def text: String = "Apply" override def onClick(): Unit = confirm() override def enabled: Boolean = tickInterval.nonEmpty } } }, Padding2D.equal(16), ) } object ChangeSimulationSpeedDialog { private val MaxUpdateInterval = 1.minute private val MinUpdateInterval = 1.micro private def validateIntervalUs(us: Long): Option[Duration] = { try { val interval = us.micros Option.when(interval >= MinUpdateInterval && interval <= MaxUpdateInterval)(interval) } catch { case _: IllegalArgumentException => None } } }