diff --git a/.idea/cssdialects.xml b/.idea/cssdialects.xml
new file mode 100644
index 0000000..54c31ad
--- /dev/null
+++ b/.idea/cssdialects.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/befunge/befunge.iml b/befunge/befunge.iml
index da87f9f..9abdb7e 100644
--- a/befunge/befunge.iml
+++ b/befunge/befunge.iml
@@ -46,5 +46,14 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/befunge/src/main/kotlin/befide/befunge/state/Vec.kt b/befunge/src/main/kotlin/befide/befunge/state/Vec.kt
index 0866d1f..fb6f263 100644
--- a/befunge/src/main/kotlin/befide/befunge/state/Vec.kt
+++ b/befunge/src/main/kotlin/befide/befunge/state/Vec.kt
@@ -10,4 +10,5 @@ data class Vec(val x: Int, val y: Int) {
operator fun times(c: Int) = Vec(x * c, y * c)
infix fun mod(other: Vec) = Vec(x mod other.x, y mod other.y)
+ operator fun unaryMinus() = Vec(-x, -y)
}
\ No newline at end of file
diff --git a/ide/ide.iml b/ide/ide.iml
index bf8f97e..7fa9950 100644
--- a/ide/ide.iml
+++ b/ide/ide.iml
@@ -47,6 +47,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ide/src/main/kotlin/befide/ide/ActionView.kt b/ide/src/main/kotlin/befide/ide/ActionView.kt
index 22a5d99..0ea2060 100644
--- a/ide/src/main/kotlin/befide/ide/ActionView.kt
+++ b/ide/src/main/kotlin/befide/ide/ActionView.kt
@@ -6,7 +6,7 @@ import javafx.animation.Timeline
import javafx.util.Duration
import tornadofx.*
-class ActionView(val interp: Interpreter, val ioView: IOView) : View() {
+class ActionView(val interp: Interpreter, val codeView: CodeView, val ioView: IOView) : View() {
var runTimeline: Timeline = timeline(false) {
keyframe(Duration.seconds(0.0)) {
setOnFinished {
@@ -21,25 +21,36 @@ class ActionView(val interp: Interpreter, val ioView: IOView) : View() {
override val root = hbox {
button("step") {
- setOnAction { interp.step() }
+ setOnAction {
+ interp.funge.setString(codeView.src)
+ interp.step()
+ }
}
button("reset") {
+ enableWhen(codeView.lockedProperty)
+
setOnAction {
interp.reset()
ioView.reset()
+ codeView.src = interp.funge.toString()
+ codeView.locked = false
}
}
button("run") {
setOnAction {
- runTimeline.rate = 10000000.0
+ interp.funge.setString(codeView.src)
+ codeView.locked = true
+ runTimeline.rate = 10000.0
runTimeline.playFromStart()
}
}
button("walk") {
setOnAction {
+ interp.funge.setString(codeView.src)
+ codeView.locked = true
runTimeline.rate = 50.0
runTimeline.playFromStart()
}
@@ -47,6 +58,8 @@ class ActionView(val interp: Interpreter, val ioView: IOView) : View() {
button("crawl") {
setOnAction {
+ interp.funge.setString(codeView.src)
+ codeView.locked = true
runTimeline.rate = 4.0
runTimeline.playFromStart()
}
diff --git a/ide/src/main/kotlin/befide/ide/CodeLabel.kt b/ide/src/main/kotlin/befide/ide/CodeLabel.kt
new file mode 100644
index 0000000..5396586
--- /dev/null
+++ b/ide/src/main/kotlin/befide/ide/CodeLabel.kt
@@ -0,0 +1,37 @@
+package befide.ide
+
+import befide.befunge.core.Interpreter
+import befide.befunge.state.Vec
+import javafx.beans.property.ObjectProperty
+import javafx.beans.property.SimpleObjectProperty
+import javafx.scene.control.Label
+import tornadofx.*
+
+class CodeLabel(val pos: Vec, val cursorPos: ObjectProperty, val interp: Interpreter) : Label() {
+ val charProperty = SimpleObjectProperty('\u0000')
+ var char: Char by charProperty
+
+ fun restyle() {
+ styleClass.setAll("code")
+
+ if (char in "0123456789") styleClass.add("code-num")
+ if (char in "gp") styleClass.add("code-funge")
+ if (char in "<>^v?#") styleClass.add("code-dir")
+
+ if (pos == cursorPos.value) styleClass.add("code-cursor")
+ if (pos == interp.ip.pos) styleClass.add("code-cursor-ip")
+ if (char == '\u2022') styleClass.add("unknown")
+ }
+
+ init {
+ textProperty().bind(charProperty.stringBinding { it?.toString() ?: " " })
+
+ setOnMouseClicked {
+ cursorPos.value = pos
+ }
+
+ charProperty.addListener { _, _, _ -> restyle() }
+
+ char = ' '
+ }
+}
\ No newline at end of file
diff --git a/ide/src/main/kotlin/befide/ide/CodeView.kt b/ide/src/main/kotlin/befide/ide/CodeView.kt
index 185b083..2fdf773 100644
--- a/ide/src/main/kotlin/befide/ide/CodeView.kt
+++ b/ide/src/main/kotlin/befide/ide/CodeView.kt
@@ -1,20 +1,131 @@
package befide.ide
import befide.befunge.core.Interpreter
-import javafx.beans.property.SimpleStringProperty
+import befide.befunge.state.Vec
+import javafx.beans.property.ObjectProperty
+import javafx.beans.property.SimpleBooleanProperty
+import javafx.beans.property.SimpleObjectProperty
+import javafx.scene.input.KeyCode
import tornadofx.*
+import tornadofx.getValue
+import tornadofx.setValue
+
+operator fun List>.get(v: Vec): T = this[v.y][v.x]
class CodeView(val interp: Interpreter) : View() {
- val srcProperty = SimpleStringProperty("")
- var src by srcProperty
+ val cursorPosProperty: ObjectProperty = SimpleObjectProperty(Vec(0, 0))
+ var cursorPos by cursorPosProperty
+
+ val cursorDeltaProperty = SimpleObjectProperty(Vec(1, 0))
+ var cursorDelta by cursorDeltaProperty
+
+ val lockedProperty = SimpleBooleanProperty(false)
+ var locked by lockedProperty
+
+ var labels: List> = List(25) { y -> List(80) { x -> CodeLabel(Vec(x, y), cursorPosProperty, interp) } }
init {
- interp.fungeChanged += { src = interp.funge.toString() }
- srcProperty.addListener { _, _, newValue -> interp.funge.setString(newValue) }
+ cursorPosProperty.addListener { _, old, new ->
+ labels[old].restyle()
+ labels[new].restyle()
+ }
+
+ interp.ipChanged += {
+ labels[it.from.pos].restyle()
+ labels[it.to.pos].restyle()
+ }
+
+ interp.fungeChanged += {
+ for (change in it.changes) {
+ labels[change.vec].char = change.to.asChar ?: '\u2022'
+ labels[change.vec].restyle()
+ }
+ }
}
- override val root = textarea(srcProperty) {
- prefRowCount = 25
- prefColumnCount = 80
+ fun move(delta: Vec? = null) {
+ cursorPos = interp.funge.nextVec(cursorPos, delta ?: cursorDelta)
+ }
+
+ var src: String
+ get() = labels.joinToString("\n") { row ->
+ row.dropLastWhile { lbl ->
+ lbl.char.isWhitespace()
+ }.joinToString("") { lbl ->
+ lbl.char.toString()
+ }
+ }
+ set(value) {
+ val lines = value.lines()
+
+ for (row in labels) {
+ for (lbl in row) {
+ lbl.char = lines.getOrNull(lbl.pos.y)?.getOrNull(lbl.pos.x) ?: ' '
+ }
+ }
+ }
+
+ override val root = hbox {
+ isFocusTraversable = true
+
+ addClass("code-view")
+
+ vbox {
+ children.setAll(labels.map { row -> hbox { children.setAll(row) } })
+ }
+
+ setOnMouseClicked {
+ requestFocus()
+ }
+
+ setOnKeyPressed {
+ when (it.code) {
+ KeyCode.RIGHT -> move(Vec(1, 0))
+ KeyCode.LEFT -> move(Vec(-1, 0))
+ KeyCode.DOWN -> move(Vec(0, 1))
+ KeyCode.UP -> move(Vec(0, -1))
+ else -> return@setOnKeyPressed
+ }
+ if (it.isAltDown) when (it.code) {
+ KeyCode.RIGHT -> cursorDelta = Vec(1, 0)
+ KeyCode.LEFT -> cursorDelta = Vec(-1, 0)
+ KeyCode.DOWN -> cursorDelta = Vec(0, 1)
+ KeyCode.UP -> cursorDelta = Vec(0, -1)
+ else -> Unit
+ }
+ it.consume()
+ }
+
+ setOnKeyTyped {
+ if (locked) return@setOnKeyTyped
+
+ for (ch in it.character) {
+ when {
+ !ch.isISOControl() -> {
+ cursorDelta = when (ch) {
+ '>' -> Vec(1, 0)
+ '<' -> Vec(-1, 0)
+ 'v' -> Vec(0, 1)
+ '^' -> Vec(0, -1)
+ else -> cursorDelta
+ }
+
+ labels[cursorPos].char = ch
+
+ move()
+ }
+
+ ch == '\u0008' -> { // backspace
+ move(-cursorDelta)
+
+ labels[cursorPos].char = ' '
+ }
+
+ else -> {
+ println("'$ch' (${ch.toInt()})")
+ }
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/ide/src/main/kotlin/befide/ide/EditorView.kt b/ide/src/main/kotlin/befide/ide/EditorView.kt
index 2403271..567a216 100644
--- a/ide/src/main/kotlin/befide/ide/EditorView.kt
+++ b/ide/src/main/kotlin/befide/ide/EditorView.kt
@@ -10,18 +10,14 @@ class EditorView : View("Befide") {
private val codeView = CodeView(interp)
private val stackView = StackView(interp)
private val ioView = IOView(interp)
- private val actionView = ActionView(interp, ioView)
+ private val actionView = ActionView(interp, codeView, ioView)
override val root = borderpane {
top { add(actionView) }
- center {
- add(codeView)
- }
+ center { add(codeView) }
- right {
- add(stackView)
- }
+ right { add(stackView) }
bottom { add(ioView) }
}
@@ -31,31 +27,13 @@ class EditorView : View("Befide") {
^ 0 v +1\ _^#-+*< >22g02g*"_@"*-!1- #v_v>
>:>::3g: ,\188 ^^ -1\g21\g22