mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-13 08:04:03 +09:00
even more emulator gui(2)
This commit is contained in:
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -52,7 +52,7 @@ class VM(
|
|||||||
var getErrorStream: () -> OutputStream = { TODO() }
|
var getErrorStream: () -> OutputStream = { TODO() }
|
||||||
var getInputStream: () -> InputStream = { TODO() }
|
var getInputStream: () -> InputStream = { TODO() }
|
||||||
|
|
||||||
var startTime: Long = -1
|
var startTime: Long = -1; private set
|
||||||
|
|
||||||
var resetDown = false
|
var resetDown = false
|
||||||
var stopDown = false
|
var stopDown = false
|
||||||
@@ -117,8 +117,14 @@ class VM(
|
|||||||
killAllContexts()
|
killAllContexts()
|
||||||
usermem.destroy()
|
usermem.destroy()
|
||||||
peripheralTable.forEach { it.peripheral?.dispose() }
|
peripheralTable.forEach { it.peripheral?.dispose() }
|
||||||
|
disposed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To check if the VM has started, check if startTime >= 0
|
||||||
|
*/
|
||||||
|
var disposed = false; private set
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return system uptime in milliseconds
|
* @return system uptime in milliseconds
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
|||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2022-10-25.
|
* Created by minjaesong on 2022-10-25.
|
||||||
*/
|
*/
|
||||||
interface EmuMenu {
|
abstract class EmuMenu(val parent: VMEmuExecutable, val x: Int, val y: Int, val w: Int, val h: Int) {
|
||||||
|
|
||||||
fun update()
|
abstract fun show()
|
||||||
|
abstract fun hide()
|
||||||
fun render(batch: SpriteBatch)
|
abstract fun update()
|
||||||
|
abstract fun render(batch: SpriteBatch)
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,19 +2,69 @@ package net.torvald.tsvm
|
|||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
|
import net.torvald.tsvm.VMEmuExecutableWrapper.Companion.FONT
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2022-10-25.
|
* Created by minjaesong on 2022-10-25.
|
||||||
*/
|
*/
|
||||||
class ProfilesMenu(val w: Int, val h: Int) : EmuMenu {
|
class ProfilesMenu(parent: VMEmuExecutable, x: Int, y: Int, w: Int, h: Int) : EmuMenu(parent, x, y, w, h) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val PROFILES_ROWS = 17 // 1 profile-row takes up 2 text-rows
|
||||||
|
}
|
||||||
|
|
||||||
|
private val profileNames = ArrayList<String>()
|
||||||
|
private var profilesScroll = 0
|
||||||
|
|
||||||
|
private var selectedProfileIndex: Int? = null
|
||||||
|
|
||||||
|
private fun resetState() {
|
||||||
|
profilesScroll = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun show() {
|
||||||
|
profileNames.clear()
|
||||||
|
profileNames.addAll(parent.profiles.keys.sorted())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hide() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override fun update() {
|
override fun update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(batch: SpriteBatch) {
|
override fun render(batch: SpriteBatch) {
|
||||||
batch.inUse {
|
batch.inUse {
|
||||||
batch.color = Color.LIME
|
batch.color = EmulatorGuiToolkit.Theme.COL_WELL
|
||||||
batch.fillRect(0, 0, w, h)
|
it.fillRect(10, 11, 228, 446)
|
||||||
|
|
||||||
|
for (i in 0 until Math.min(PROFILES_ROWS, profileNames.size)) {
|
||||||
|
val index = profilesScroll + i
|
||||||
|
|
||||||
|
val colBack = if (index == selectedProfileIndex) EmulatorGuiToolkit.Theme.COL_HIGHLIGHT
|
||||||
|
else if (i % 2 == 0) EmulatorGuiToolkit.Theme.COL_WELL
|
||||||
|
else EmulatorGuiToolkit.Theme.COL_WELL2
|
||||||
|
val colFore = if (index == selectedProfileIndex) EmulatorGuiToolkit.Theme.COL_ACTIVE
|
||||||
|
else EmulatorGuiToolkit.Theme.COL_ACTIVE2
|
||||||
|
|
||||||
|
val theVM = parent.getVMbyProfileName(profileNames[index])
|
||||||
|
val isVMrunning = if (theVM != null) !theVM.disposed && theVM.startTime >= 0 else false
|
||||||
|
val vmViewport = parent.getViewportForTheVM(theVM)
|
||||||
|
|
||||||
|
val vmRunStatusText = if (isVMrunning) "Running" else "Idle"
|
||||||
|
val vmViewportText = if (vmViewport != null) "on viewport #${vmViewport+1}" else "hidden"
|
||||||
|
|
||||||
|
batch.color = colBack
|
||||||
|
it.fillRect(10, 11 + i*2*FONT.H, 228, 26)
|
||||||
|
|
||||||
|
batch.color = colFore
|
||||||
|
FONT.draw(batch, profileNames[index], 12f, 11f + i*2*FONT.H)
|
||||||
|
batch.color = EmulatorGuiToolkit.Theme.COL_ACTIVE3
|
||||||
|
FONT.draw(batch, "$vmRunStatusText, $vmViewportText", 12f, 11f+FONT.H + i*2*FONT.H)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,7 +98,18 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
|
|
||||||
val profiles = HashMap<String, JsonValue>()
|
val profiles = HashMap<String, JsonValue>()
|
||||||
|
|
||||||
fun writeProfilesToFile(outFile: FileHandle) {
|
private val currentlyLoadedProfiles = HashMap<String, VM>()
|
||||||
|
fun getVMbyProfileName(name: String): VM? {
|
||||||
|
if (profiles.containsKey(name)) {
|
||||||
|
return currentlyLoadedProfiles.getOrPut(name) { _makeVMfromJson(profiles[name]!!) }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getViewportForTheVM(vm: VM?): Int? = if (vm == null) null else vms.indexOfFirst { vm.id == it?.vm?.id }.let { if (it < 0) null else it }
|
||||||
|
|
||||||
|
private fun writeProfilesToFile(outFile: FileHandle) {
|
||||||
val out = StringBuilder()
|
val out = StringBuilder()
|
||||||
out.append('{')
|
out.append('{')
|
||||||
|
|
||||||
@@ -116,6 +127,7 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
outFile.writeString(outstr, false)
|
outFile.writeString(outstr, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun create() {
|
override fun create() {
|
||||||
super.create()
|
super.create()
|
||||||
|
|
||||||
@@ -151,7 +163,7 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
vms[0] = VMRunnerInfo(vm, "Initial VM")*/
|
vms[0] = VMRunnerInfo(vm, "Initial VM")*/
|
||||||
|
|
||||||
val testJson = JsonReader().parse("{$defaultProfile}")
|
val testJson = JsonReader().parse("{$defaultProfile}")
|
||||||
val vm1 = makeVMfromJson(testJson.get("Initial VM"))
|
val vm1 = getVMbyProfileName("Initial VM")!!
|
||||||
initVMenv(vm1)
|
initVMenv(vm1)
|
||||||
vms[0] = VMRunnerInfo(vm1, "Initial VM")
|
vms[0] = VMRunnerInfo(vm1, "Initial VM")
|
||||||
|
|
||||||
@@ -267,7 +279,7 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
updateMenu()
|
updateMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val defaultGuiBackgroundColour = Color(0x303039ff)
|
val defaultGuiBackgroundColour = Color(0x303039ff)
|
||||||
|
|
||||||
private fun renderGame(delta: Float) {
|
private fun renderGame(delta: Float) {
|
||||||
vms.forEachIndexed { index, vmInfo ->
|
vms.forEachIndexed { index, vmInfo ->
|
||||||
@@ -369,13 +381,24 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
|
|
||||||
private val menuTabW = windowWidth - 4
|
private val menuTabW = windowWidth - 4
|
||||||
private val menuTabH = windowHeight - 4 - FONT.H
|
private val menuTabH = windowHeight - 4 - FONT.H
|
||||||
|
private val menuTabX = windowWidth * (panelsX-1) + 2
|
||||||
|
private val menuTabY =windowHeight * (panelsY-1) + FONT.H + 2
|
||||||
|
|
||||||
private val menuTabs = listOf("Profiles", "Machine", "Peripherals", "Cards")
|
private val menuTabs = listOf("Profiles", "Machine", "COMs", "Cards", "Setup")
|
||||||
private val tabPos = (menuTabs + "").mapIndexed { index, _ -> 1 + menuTabs.subList(0, index).sumBy { it.length } + 2 * index }
|
private val tabPos = (menuTabs + "").mapIndexed { index, _ -> 1 + menuTabs.subList(0, index).sumBy { it.length } + 2 * index }
|
||||||
private val tabs = listOf(ProfilesMenu(menuTabW, menuTabH))
|
private val tabs = listOf(ProfilesMenu(this, menuTabX, menuTabY, menuTabW, menuTabH))
|
||||||
private var menuTabSel = 0
|
private var menuTabSel = 0
|
||||||
|
|
||||||
|
private var tabChangeRequested: Int? = 0 // null: not requested
|
||||||
|
|
||||||
private fun drawMenu(batch: SpriteBatch, x: Float, y: Float) {
|
private fun drawMenu(batch: SpriteBatch, x: Float, y: Float) {
|
||||||
|
if (tabChangeRequested != null) {
|
||||||
|
tabs[menuTabSel].hide()
|
||||||
|
tabs[tabChangeRequested!!].show()
|
||||||
|
menuTabSel = tabChangeRequested!!
|
||||||
|
tabChangeRequested = null
|
||||||
|
}
|
||||||
|
|
||||||
batch.inUse {
|
batch.inUse {
|
||||||
// background for the entire area
|
// background for the entire area
|
||||||
batch.color = defaultGuiBackgroundColour
|
batch.color = defaultGuiBackgroundColour
|
||||||
@@ -403,7 +426,7 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// draw the window frame inside the tab
|
// draw the window frame inside the tab
|
||||||
batch.color = EmulatorGuiToolkit.Theme.COL_INACTIVE
|
batch.color = EmulatorGuiToolkit.Theme.COL_LAND
|
||||||
batch.fillRect(x, y + FONT.H, windowWidth, windowHeight - FONT.H)
|
batch.fillRect(x, y + FONT.H, windowWidth, windowHeight - FONT.H)
|
||||||
batch.color = EmulatorGuiToolkit.Theme.COL_HIGHLIGHT
|
batch.color = EmulatorGuiToolkit.Theme.COL_HIGHLIGHT
|
||||||
batch.fillRect(x, y + FONT.H, windowWidth.toFloat(), 2f)
|
batch.fillRect(x, y + FONT.H, windowWidth.toFloat(), 2f)
|
||||||
@@ -412,7 +435,7 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
batch.fillRect(x + windowWidth - 2f, y + FONT.H, 2f, windowHeight - FONT.H - 2f)
|
batch.fillRect(x + windowWidth - 2f, y + FONT.H, 2f, windowHeight - FONT.H - 2f)
|
||||||
}
|
}
|
||||||
|
|
||||||
setCameraPosition(windowWidth * (panelsX-1) + 2f, windowHeight * (panelsY-1) + FONT.H + 2f)
|
setCameraPosition(menuTabX.toFloat(), menuTabY.toFloat())
|
||||||
tabs[menuTabSel].render(batch)
|
tabs[menuTabSel].render(batch)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,6 +463,7 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* You'll want to further init the things using the VM this function returns, such as:
|
* You'll want to further init the things using the VM this function returns, such as:
|
||||||
*
|
*
|
||||||
@@ -450,7 +474,7 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX:
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
private fun makeVMfromJson(json: JsonValue): VM {
|
private fun _makeVMfromJson(json: JsonValue): VM {
|
||||||
val assetsDir = json.getString("assetsdir")
|
val assetsDir = json.getString("assetsdir")
|
||||||
val ramsize = json.getLong("ramsize")
|
val ramsize = json.getLong("ramsize")
|
||||||
val cardslots = json.getInt("cardslots")
|
val cardslots = json.getInt("cardslots")
|
||||||
@@ -547,10 +571,15 @@ object EmulatorGuiToolkit {
|
|||||||
val COL_INACTIVE2 = Color(0x5a5a5fff.toInt())
|
val COL_INACTIVE2 = Color(0x5a5a5fff.toInt())
|
||||||
val COL_ACTIVE = Color(0x23ff00ff.toInt()) // neon green
|
val COL_ACTIVE = Color(0x23ff00ff.toInt()) // neon green
|
||||||
val COL_ACTIVE2 = Color(0xfff600ff.toInt()) // yellow
|
val COL_ACTIVE2 = Color(0xfff600ff.toInt()) // yellow
|
||||||
|
val COL_ACTIVE3 = Color.WHITE
|
||||||
val COL_HIGHLIGHT = Color(0xe43380ff.toInt()) // magenta
|
val COL_HIGHLIGHT = Color(0xe43380ff.toInt()) // magenta
|
||||||
val COL_DISABLED = Color(0xaaaaaaff.toInt())
|
val COL_DISABLED = Color(0xaaaaaaff.toInt())
|
||||||
|
|
||||||
val COL_TAB_NOT_SELECTED = Color(0x503cd4ff) // dark blue
|
val COL_TAB_NOT_SELECTED = Color(0x503cd4ff) // dark blue
|
||||||
|
|
||||||
|
val COL_LAND = Color(0x6b8ba2ff.toInt())
|
||||||
|
val COL_WELL = Color(0x374854ff.toInt())
|
||||||
|
val COL_WELL2 = Color(0x3e5261ff.toInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user