summaryrefslogtreecommitdiff
path: root/src/main/scala/graphyx/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/graphyx/gui')
-rw-r--r--src/main/scala/graphyx/gui/AboutHelpFrame.scala24
-rw-r--r--src/main/scala/graphyx/gui/BodyPopup.scala41
-rw-r--r--src/main/scala/graphyx/gui/Container.scala37
-rw-r--r--src/main/scala/graphyx/gui/ControlPanel.scala40
-rw-r--r--src/main/scala/graphyx/gui/GravityPanel.scala83
-rw-r--r--src/main/scala/graphyx/gui/InfoPanel.scala30
-rw-r--r--src/main/scala/graphyx/gui/MainFrame.scala25
-rw-r--r--src/main/scala/graphyx/gui/MainPanel.scala77
-rw-r--r--src/main/scala/graphyx/gui/MenuHelp.scala19
-rw-r--r--src/main/scala/graphyx/gui/MenuPanel.scala12
-rw-r--r--src/main/scala/graphyx/gui/OptionsPanel.scala128
-rw-r--r--src/main/scala/graphyx/gui/PopupMenu.scala20
-rw-r--r--src/main/scala/graphyx/gui/ShapeInfoPanel.scala35
-rw-r--r--src/main/scala/graphyx/gui/WorldPanel.scala179
14 files changed, 750 insertions, 0 deletions
diff --git a/src/main/scala/graphyx/gui/AboutHelpFrame.scala b/src/main/scala/graphyx/gui/AboutHelpFrame.scala
new file mode 100644
index 0000000..0bb3c36
--- /dev/null
+++ b/src/main/scala/graphyx/gui/AboutHelpFrame.scala
@@ -0,0 +1,24 @@
+package graphyx.gui
+
+import graphyx.actors._
+import graphyx.gui._
+import scala.swing._
+import scala.swing.event._
+
+class AboutHelpFrame extends Frame {
+ title = "About"
+ contents = new TextArea(
+ """|Graphyx, testing and visualization tool for SiMS.
+ |
+ |copyright (c) 2009 Jakob Odersky
+ |SiMS and Graphyx are made available under the MIT License
+ |
+ |https://github.com/jodersky/sims
+ |
+ |Version 1.2""".stripMargin
+ ) {editable = false}
+}
+
+object AboutHelpFrame {
+ val frame = new AboutHelpFrame
+}
diff --git a/src/main/scala/graphyx/gui/BodyPopup.scala b/src/main/scala/graphyx/gui/BodyPopup.scala
new file mode 100644
index 0000000..998a440
--- /dev/null
+++ b/src/main/scala/graphyx/gui/BodyPopup.scala
@@ -0,0 +1,41 @@
+/*
+ * Graphyx
+ * copyright (c) 2009 Jakob Odersky
+ * made available under the MIT License
+*/
+
+package graphyx.gui
+
+import scala.swing._
+import scala.swing.event._
+import sims.dynamics._
+import graphyx.graphics._
+
+class BodyPopup extends PopupMenu {
+ private var b: Body = _
+ def body = b
+ def body_=(newBody: Body) = {
+ b = newBody
+ chckFixed.selected = b.fixed
+ chckMonitor.selected = b.monitor
+ }
+
+ val chckMonitor = new CheckMenuItem("Monitor")
+ val chckFixed = new CheckMenuItem("Fixed")
+ val btnClose = new MenuItem("Close")
+
+ add(chckMonitor)
+ add(chckFixed)
+ add(btnClose)
+ listenTo(chckMonitor, chckFixed, btnClose)
+ reactions += {
+ case ButtonClicked(b) => {setVisible(false)
+ b match {
+ case `chckMonitor` => body.monitor = chckMonitor.selected
+ case `chckFixed` => body.fixed = chckFixed.selected
+ case `btnClose` => ()
+ case _ => ()
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/scala/graphyx/gui/Container.scala b/src/main/scala/graphyx/gui/Container.scala
new file mode 100644
index 0000000..80886f8
--- /dev/null
+++ b/src/main/scala/graphyx/gui/Container.scala
@@ -0,0 +1,37 @@
+/*
+ * Graphyx
+ * copyright (c) 2009 Jakob Odersky
+ * made available under the MIT License
+*/
+
+package graphyx.gui
+
+import sims.dynamics._
+import graphyx.graphics._
+import java.io._
+class Container {
+ val mainFrame = new MainFrame(this)
+
+ //val plotFrames = new ArrayBuffer[plot.PlotFrame[Body]]
+
+ var scene: Scene = Scene(new World)
+
+ def show() = {
+ mainFrame.visible = true
+ }
+
+ def update(s: Scene) = {
+ scene = s
+ mainFrame.mainPanel.controlPanel.update()
+ mainFrame.mainPanel.worldPanel.update()
+ mainFrame.mainPanel.infoPanel.update()
+ mainFrame.mainPanel.optionsPanel.update()
+ mainFrame.mainPanel.gravityPanel.update()
+ }
+
+ def exitGUI() = {
+ mainFrame.dispose
+ AboutHelpFrame.frame.dispose
+ //plotFrames.foreach(_.dispose)
+ }
+}
diff --git a/src/main/scala/graphyx/gui/ControlPanel.scala b/src/main/scala/graphyx/gui/ControlPanel.scala
new file mode 100644
index 0000000..43d7305
--- /dev/null
+++ b/src/main/scala/graphyx/gui/ControlPanel.scala
@@ -0,0 +1,40 @@
+/*
+ * Graphyx
+ * copyright (c) 2009 Jakob Odersky
+ * made available under the MIT License
+*/
+
+package graphyx.gui
+
+import graphyx._
+import graphyx.actors._
+import graphyx.gui._
+import scala.swing._
+import scala.swing.event._
+
+class ControlPanel(container: Container) extends BoxPanel(Orientation.Horizontal) {
+ val btnStart = new Button {text = "Start"} //; icon = new javax.swing.ImageIcon("""play.png"""); tooltip = "Start"}
+ val btnStep = new Button {text = "Step"}
+ val btnStop = new Button {text = "Stop"}
+ val btnExit = new Button {text = "Exit"}
+ val btnFire = new Button {text = "Fire!"}
+ val btnReset = new Button {text = "Reset"}
+ val cboTest = new ComboBox(Graphyx.tests)
+
+ contents ++= List(btnStart, btnStep, btnStop, btnExit, new Separator, btnFire, btnReset, cboTest)
+
+ listenTo(btnStart, btnStep, btnStop, btnExit, btnFire, btnReset, cboTest.selection)
+ reactions += {
+ case ButtonClicked(`btnStart`) => Graphyx.physicsActor ! Start
+ case ButtonClicked(`btnStop`) => Graphyx.physicsActor ! Stop
+ case ButtonClicked(`btnStep`) => Graphyx.physicsActor ! Step
+ case ButtonClicked(`btnExit`) => Graphyx.exit
+ case ButtonClicked(`btnFire`) => Graphyx.physicsActor ! FireEvent
+ case ButtonClicked(`btnReset`) => Graphyx.test = Graphyx.tests(cboTest.selection.index)
+ case SelectionChanged(`cboTest`) => Graphyx.test = Graphyx.tests(cboTest.selection.index)
+ }
+
+ def update() {
+ btnFire.enabled = Graphyx.test.enableEvent
+ }
+}
diff --git a/src/main/scala/graphyx/gui/GravityPanel.scala b/src/main/scala/graphyx/gui/GravityPanel.scala
new file mode 100644
index 0000000..bdf5245
--- /dev/null
+++ b/src/main/scala/graphyx/gui/GravityPanel.scala
@@ -0,0 +1,83 @@
+/*
+ * Graphyx
+ * copyright (c) 2009 Jakob Odersky
+ * made available under the MIT License
+*/
+
+package graphyx.gui
+
+import scala.swing._
+import scala.swing.event._
+import scala.swing.GridBagPanel._
+import sims.geometry._
+
+class GravityPanel(container: Container) extends GridBagPanel{
+
+ val c = new Constraints
+ c.fill = Fill.Both
+ this.border = Swing.EmptyBorder(3,3,3,3)
+
+ val sldX = new Slider {max = 500; min = -500; preferredSize = minimumSize}
+ val lblX = new Label("0.0")
+ val sldY = new Slider {max = 500; min = -500; preferredSize = minimumSize}
+ val lblY = new Label("-9.81")
+
+ c.gridx = 0
+ c.gridy = 0
+ c.weightx = 1.0
+ c.weighty = 0.0
+ super.add(new Label("Gravity"), c)
+
+ c.gridx = 0
+ c.gridy = 1
+ c.weightx = 1.0
+ c.weighty = 0.0
+ super.add(new Label("X: "), c)
+
+ c.gridx = 1
+ c.gridy = 1
+ c.weightx = 1.0
+ c.weighty = 0.0
+ super.add(sldX, c)
+
+ c.gridx = 2
+ c.gridy = 1
+ c.weightx = 0.0
+ c.weighty = 0.0
+ super.add(lblX, c)
+
+ c.gridx = 0
+ c.gridy = 2
+ c.weightx = 1.0
+ c.weighty = 0.0
+ super.add(new Label("Y: "), c)
+
+ c.gridx = 1
+ c.gridy = 2
+ c.weightx = 1.0
+ c.weighty = 0.0
+ super.add(sldY, c)
+
+ c.gridx = 2
+ c.gridy = 2
+ c.weightx = 0.0
+ c.weighty = 0.0
+ super.add(lblY, c)
+
+
+ listenTo(sldX, sldY)
+
+ reactions += {
+ case ValueChanged(s) if (s == sldX || s == sldY) =>
+ container.scene.real.gravity = Vector2D(sldX.value / 10.0, sldY.value / 10.0)
+ }
+
+ def update() = {
+ val g = container.scene.world.gravity
+ sldX.value = (g.x * 10).toInt
+ lblX.text = ((g.x * 10).toInt / 10.0).toString
+ sldY.value = (g.y * 10).toInt
+ lblY.text = ((g.y * 10).toInt / 10.0).toString
+ }
+
+}
diff --git a/src/main/scala/graphyx/gui/InfoPanel.scala b/src/main/scala/graphyx/gui/InfoPanel.scala
new file mode 100644
index 0000000..d9dad43
--- /dev/null
+++ b/src/main/scala/graphyx/gui/InfoPanel.scala
@@ -0,0 +1,30 @@
+/*
+ * Graphyx
+ * copyright (c) 2009 Jakob Odersky
+ * made available under the MIT License
+*/
+
+package graphyx.gui
+
+import scala.swing._
+import scala.swing._
+
+class InfoPanel(container: Container) extends BoxPanel(Orientation.Vertical){
+ preferredSize = new java.awt.Dimension(200, 50)
+
+ val out = new TextArea
+ out.editable = false
+ contents += out
+ border = Swing.EmptyBorder(3,3,3,3)
+
+ def update() = {
+ out.text = "fps=" + container.scene.fps + "\n" +
+ "t=" + container.scene.world.time.formatted("%f") + "\n"
+ if (container.scene.world.overCWarning) {
+ out.foreground = java.awt.Color.red
+ out.text += "Warning: some bodies passed the speed of light! Simulation may be highly incorrect.\n"
+ }
+ else out.foreground = java.awt.Color.black
+ for (r <- container.scene.world.monitorFlatResults) out.text += "b" + r._1 + " " + r._2 + ": " + r._3 + "\n"
+ }
+}
diff --git a/src/main/scala/graphyx/gui/MainFrame.scala b/src/main/scala/graphyx/gui/MainFrame.scala
new file mode 100644
index 0000000..4fdc9a2
--- /dev/null
+++ b/src/main/scala/graphyx/gui/MainFrame.scala
@@ -0,0 +1,25 @@
+/*
+ * Graphyx
+ * copyright (c) 2009 Jakob Odersky
+ * made available under the MIT License
+*/
+
+package graphyx.gui
+
+import graphyx._
+import sims._
+import scala.swing._
+
+class MainFrame(container: Container) extends Frame{
+ super.background = java.awt.Color.WHITE
+ title = "graphyx"
+ preferredSize = new java.awt.Dimension(1000,800)
+
+ reactions += {
+ case event.WindowClosing(w) => Graphyx.exit()
+ }
+
+ val mainPanel = new MainPanel(container)
+ contents = mainPanel
+
+}
diff --git a/src/main/scala/graphyx/gui/MainPanel.scala b/src/main/scala/graphyx/gui/MainPanel.scala
new file mode 100644
index 0000000..e4989e8
--- /dev/null
+++ b/src/main/scala/graphyx/gui/MainPanel.scala
@@ -0,0 +1,77 @@
+/*
+ * Graphyx
+ * copyright (c) 2009 Jakob Odersky
+ * made available under the MIT License
+*/
+
+package graphyx.gui
+
+import graphyx.graphics._
+import sims._
+import scala.swing._
+import swing.event._
+import GridBagPanel._
+import java.awt.Insets
+
+class MainPanel(container: Container) extends scala.swing.GridBagPanel {
+ val c = new Constraints
+
+ val menuPanel = new MenuPanel(container)
+ val worldPanel = new WorldPanel(container)
+ val controlPanel = new ControlPanel(container)
+ val infoPanel = new InfoPanel(container)
+ val optionsPanel = new OptionsPanel(container)
+ val shapeInfoPanel = new ShapeInfoPanel(container)
+ val gravityPanel = new GravityPanel(container)
+
+ val splitter = new SplitPane {
+ orientation = Orientation.Vertical
+ continuousLayout = true
+ resizeWeight = 1
+ dividerSize = 2
+ leftComponent = worldPanel
+ rightComponent = new SplitPane {
+ orientation = Orientation.Horizontal
+ continuousLayout = true
+ resizeWeight = 1
+ dividerSize = 2
+ topComponent = new SplitPane{
+ orientation = Orientation.Horizontal
+ continuousLayout = true
+ resizeWeight = 1
+ dividerSize = 2
+ topComponent = infoPanel
+ bottomComponent = gravityPanel
+ }
+ bottomComponent = optionsPanel
+ }
+ }
+ c.fill = Fill.Both
+
+ c.gridx = 0
+ c.gridy = 0
+ c.weightx = 1.0
+ c.weighty = 0.0
+ super.add(menuPanel, c)
+
+ c.gridx = 0
+ c.gridy = 1
+ c.weightx = 1.0
+ c.weighty = 0.0
+ super.add(controlPanel, c)
+
+
+ c.gridx = 0
+ c.gridy = 2
+ c.weightx = 1.0
+ c.weighty = 1.0
+ super.add(splitter, c)
+
+ /*
+ c.gridx = 1
+ c.gridy = 1
+ c.weightx = 0.0
+ c.weighty = 1.0
+ super.add(infoPanel, c)
+ */
+}
diff --git a/src/main/scala/graphyx/gui/MenuHelp.scala b/src/main/scala/graphyx/gui/MenuHelp.scala
new file mode 100644
index 0000000..1c73d51
--- /dev/null
+++ b/src/main/scala/graphyx/gui/MenuHelp.scala
@@ -0,0 +1,19 @@
+package graphyx.gui
+
+import graphyx.actors._
+import graphyx.gui._
+import scala.swing._
+import scala.swing.event._
+
+class MenuHelp extends Menu("Help") {
+ val miAbout = new MenuItem("About...")
+
+ val components = List(miAbout)
+ contents ++= components
+
+ listenTo(components: _*)
+ reactions += {
+ case event.ButtonClicked(`miAbout`) => AboutHelpFrame.frame.visible = true
+
+ }
+}
diff --git a/src/main/scala/graphyx/gui/MenuPanel.scala b/src/main/scala/graphyx/gui/MenuPanel.scala
new file mode 100644
index 0000000..d3196fe
--- /dev/null
+++ b/src/main/scala/graphyx/gui/MenuPanel.scala
@@ -0,0 +1,12 @@
+package graphyx.gui
+
+import graphyx.actors._
+import graphyx.gui._
+import scala.swing._
+import scala.swing.event._
+
+class MenuPanel(container: Container) extends BoxPanel(Orientation.Horizontal) {
+ val mnu = new MenuBar
+ mnu.contents += new MenuHelp
+ contents += mnu
+}
diff --git a/src/main/scala/graphyx/gui/OptionsPanel.scala b/src/main/scala/graphyx/gui/OptionsPanel.scala
new file mode 100644
index 0000000..525f352
--- /dev/null
+++ b/src/main/scala/graphyx/gui/OptionsPanel.scala
@@ -0,0 +1,128 @@
+/*
+ * Graphyx
+ * copyright (c) 2009 Jakob Odersky
+ * made available under the MIT License
+*/
+
+package graphyx.gui
+
+import graphyx.graphics._
+import sims.geometry._
+import sims.dynamics._
+import scala.swing._
+import scala.swing.event._
+import GridBagPanel._
+
+class OptionsPanel(container: Container) extends GridPanel(12,2){
+ /*
+ val c = new Constraints
+ c.anchor = Anchor.West
+ */
+
+ this.border = Swing.EmptyBorder(3,3,3,3)
+ this.hGap = 3
+ this.vGap = 3
+
+ val lblTimeStep = new Label("h [Hz]") {tooltip = "Time Step"}
+ val txtTimeStep = new TextField
+
+ val lblIterations = new Label("i [1]") {tooltip = "Iterations"}
+ val txtIterations = new TextField
+
+ val lblCD = new Label("CD") {tooltip = "Collision Detection"}
+ val chckCD = new CheckBox("")
+
+ val lblPC = new Label("PC") {tooltip = "Position Correction"}
+ val chckPC = new CheckBox("")
+
+ val lblDraw = new Label("Draw")
+
+ val lblDrawBodies = new Label("Bodies")
+ val chckDrawBodies = new CheckBox {selected = false}
+
+ val lblDrawShapes = new Label("Shapes")
+ val chckDrawShapes = new CheckBox {selected = true}
+
+ val lblDrawJoints = new Label("Joints")
+ val chckDrawJoints = new CheckBox {selected = true}
+
+ val lblDrawAABBs = new Label("AABBs")
+ val chckDrawAABBs = new CheckBox {selected = false}
+
+ val lblDrawPairs = new Label("Pairs")
+ val chckDrawPairs = new CheckBox {selected = false}
+
+ val lblDrawCollisions = new Label("Collisions")
+ val chckDrawCollisions = new CheckBox {selected = false}
+
+ val lblTrace = new Label("Trace")
+ val chckTrace = new CheckBox {selected = false}
+
+ val components = List(
+ lblTimeStep, txtTimeStep,
+ lblIterations, txtIterations,
+ lblCD, chckCD,
+ lblPC, chckPC,
+ lblDraw, new Label(""),
+ lblDrawBodies, chckDrawBodies,
+ lblDrawShapes, chckDrawShapes,
+ lblDrawJoints, chckDrawJoints,
+ lblDrawAABBs, chckDrawAABBs,
+ lblDrawPairs, chckDrawPairs,
+ lblDrawCollisions, chckDrawCollisions,
+ lblTrace, chckTrace
+ )
+ contents ++= components
+ listenTo(components: _*)
+
+ reactions += {
+ case EditDone(`txtTimeStep`) => container.scene.world.real.timeStep = 1.0 / txtTimeStep.text.toInt
+ case EditDone(`txtIterations`) => container.scene.world.real.iterations = txtIterations.text.toInt
+ case ButtonClicked(`chckCD`) => container.scene.world.real.enableCollisionDetection = chckCD.selected
+ case ButtonClicked(`chckPC`) => container.scene.world.real.enablePositionCorrection = chckPC.selected
+ case ButtonClicked(`chckDrawBodies`) => container.mainFrame.mainPanel.worldPanel.drawBodies = chckDrawBodies.selected
+ case ButtonClicked(`chckDrawShapes`) => container.mainFrame.mainPanel.worldPanel.drawShapes = chckDrawShapes.selected
+ case ButtonClicked(`chckDrawJoints`) => container.mainFrame.mainPanel.worldPanel.drawJoints = chckDrawJoints.selected
+ case ButtonClicked(`chckDrawAABBs`) => container.mainFrame.mainPanel.worldPanel.drawAABBs = chckDrawAABBs.selected
+ case ButtonClicked(`chckDrawPairs`) => container.mainFrame.mainPanel.worldPanel.drawPairs = chckDrawPairs.selected
+ case ButtonClicked(`chckDrawCollisions`) => container.mainFrame.mainPanel.worldPanel.drawCollisions = chckDrawCollisions.selected
+ case ButtonClicked(`chckTrace`) => container.mainFrame.mainPanel.worldPanel.trace = chckTrace.selected
+ }
+
+ def update() = {
+ if (!txtTimeStep.peer.hasFocus)
+ txtTimeStep.text = (1.0 / container.scene.world.timeStep).toString
+ if (!txtIterations.peer.hasFocus)
+ txtIterations.text = container.scene.world.iterations.toString
+ chckCD.selected = container.scene.world.enableCollisionDetection
+ chckPC.selected = container.scene.world.enablePositionCorrection
+ chckDrawBodies.selected = container.mainFrame.mainPanel.worldPanel.drawBodies
+ chckDrawShapes.selected = container.mainFrame.mainPanel.worldPanel.drawShapes
+ chckDrawJoints.selected = container.mainFrame.mainPanel.worldPanel.drawJoints
+ chckDrawAABBs.selected = container.mainFrame.mainPanel.worldPanel.drawAABBs
+ chckDrawPairs.selected = container.mainFrame.mainPanel.worldPanel.drawPairs
+ chckDrawCollisions.selected = container.mainFrame.mainPanel.worldPanel.drawCollisions
+ chckTrace.selected = container.mainFrame.mainPanel.worldPanel.trace
+ }
+
+
+ /*
+ def addCell(cm: Component)(x: Int, y: Int) = {
+ c.gridx = x
+ c.gridy = y
+ c.weightx = 0.5
+ c.weighty = 0.0
+ c.
+ if (cm.isInstanceOf[TextArea])
+ c.fill = Fill.Horizontal
+ else
+ c.fill = Fill.None
+ super.add(cm, c)
+ }
+
+ addCell(lblTimeStep)(0,0)
+ addCell(txtTimeStep)(1,0)
+ addCell(lblIterations)(0,1)
+ addCell(txtIterations)(1,1)
+ */
+}
diff --git a/src/main/scala/graphyx/gui/PopupMenu.scala b/src/main/scala/graphyx/gui/PopupMenu.scala
new file mode 100644
index 0000000..9679018
--- /dev/null
+++ b/src/main/scala/graphyx/gui/PopupMenu.scala
@@ -0,0 +1,20 @@
+/*
+ * Graphyx
+ * copyright (c) 2009 Jakob Odersky
+ * made available under the MIT License
+*/
+
+package graphyx.gui
+
+import scala.swing._
+import scala.swing.event._
+import javax.swing._
+
+class PopupMenu extends Component
+{
+ override lazy val peer : JPopupMenu = new JPopupMenu
+
+ def add(item: MenuItem) : Unit = { peer.add(item.peer) }
+ def setVisible(visible:Boolean) : Unit = { peer.setVisible(visible) }
+ /* Create any other peer methods here */
+} \ No newline at end of file
diff --git a/src/main/scala/graphyx/gui/ShapeInfoPanel.scala b/src/main/scala/graphyx/gui/ShapeInfoPanel.scala
new file mode 100644
index 0000000..d94c0bd
--- /dev/null
+++ b/src/main/scala/graphyx/gui/ShapeInfoPanel.scala
@@ -0,0 +1,35 @@
+/*
+ * Graphyx
+ * copyright (c) 2009 Jakob Odersky
+ * made available under the MIT License
+*/
+
+package graphyx.gui
+
+import graphyx.graphics._
+import sims.geometry._
+import sims.dynamics._
+import scala.swing._
+import scala.swing.event._
+import GridBagPanel._
+
+class ShapeInfoPanel(container: Container) extends GridPanel(2,2) {
+
+ this.border = Swing.EmptyBorder(3,3,3,3)
+ this.hGap = 3
+ this.vGap = 3
+
+ val lblBody = new Label("Body")
+ val lblValBody = new Label("0")
+
+ val lblShape = new Label("Shape")
+ val lblValShape = new Label("0")
+
+ val components = List(
+ lblBody, lblValBody,
+ lblShape, lblValShape
+ )
+
+ contents ++= components
+
+}
diff --git a/src/main/scala/graphyx/gui/WorldPanel.scala b/src/main/scala/graphyx/gui/WorldPanel.scala
new file mode 100644
index 0000000..ad14726
--- /dev/null
+++ b/src/main/scala/graphyx/gui/WorldPanel.scala
@@ -0,0 +1,179 @@
+/*
+ * Graphyx
+ * copyright (c) 2009 Jakob Odersky
+ * made available under the MIT License
+*/
+
+package graphyx.gui
+
+import graphyx.graphics._
+import sims.geometry._
+import sims.dynamics._
+import scala.swing._
+import scala.swing.event._
+import scala.collection.mutable.Map
+import scala.collection.mutable.Queue
+
+class WorldPanel(container: Container) extends BoxPanel(Orientation.Vertical){
+ cursor = new java.awt.Cursor(java.awt.Cursor.CROSSHAIR_CURSOR)
+ val lblBody = new Label {text = "None @ (0, 0)"}
+ contents += lblBody
+ val popup = new BodyPopup
+ contents += popup
+
+ implicit def point2Vector(p: java.awt.Point) = {
+ val x = p.x
+ val y = size.height - p.y
+ new Vector2D((x - offset.x) / scale / ppm, (y - offset.y) / scale / ppm)
+ }
+
+ private val ppi = java.awt.Toolkit.getDefaultToolkit.getScreenResolution
+ val ppm = 39.37007874 * ppi
+ var scale = 0.02
+ var offset = Vector2D(100, 100) //vector for point coordinates [px]
+
+ def scene: Scene = container.scene
+
+ def update() = {
+ repaint()
+ }
+
+ var drawBodies = false
+ var drawShapes = true
+ var drawJoints = true
+ var drawAABBs = false
+ var drawPairs = false
+ var drawCollisions = false
+ var trace = false
+
+ override def paintComponent(g: java.awt.Graphics2D) = {
+ var parts: Seq[Drawable] = Seq()
+ if (drawShapes) parts ++= scene.shapes
+ if (drawJoints) parts ++= scene.joints
+ if (drawAABBs) parts ++= scene.aabbs
+ if (drawPairs) parts ++= scene.pairs
+ if (drawCollisions) parts ++= scene.collisions
+ if (drawBodies) parts ++= scene.bodies
+ g.clearRect(0,0,size.width,size.height)
+ drawAxes(g)
+ g.translate(offset.x.toInt, -offset.y.toInt)
+ drawParts(parts, g)
+ if (trace) trace(scene.shapes, g)
+ g.translate(-offset.x.toInt, offset.y.toInt)
+ }
+
+ def drawAxes(g: java.awt.Graphics2D): Unit = {
+ g.setColor(java.awt.Color.GRAY)
+ g.drawLine(0, size.height - offset.y.toInt, size.width, size.height - offset.y.toInt)
+ g.drawLine(offset.x.toInt, 0, offset.x.toInt, size.height)
+ /*
+ val md = scale * ppm
+ val hb = size.width / md
+ for (i <- 1 to hb.toInt) g.drawLine(offset.x.toInt + i * md.toInt, size.height - offset.y.toInt,
+ offset.x.toInt + i * md.toInt, size.height - offset.y.toInt + 10)
+ */
+ }
+
+ def drawParts(parts: Iterable[Drawable], g: java.awt.Graphics2D) = {
+ for (p <- parts){
+ p.g = g
+ p.windowHeight = super.size.height
+ p.ppm = ppm
+ p.scale = this.scale
+ p.draw()
+ }
+ }
+
+ val prevPos: Map[Int, Queue[Vector2D]] = Map()
+ def trace(shapes: Iterable[GraphicalShape], g: java.awt.Graphics2D) = {
+ for (s <- shapes) {
+ s.g = g
+ s.windowHeight = super.size.height
+ s.ppm = ppm
+ s.scale = this.scale
+
+
+ if (!prevPos.contains(s.uid)) prevPos += (s.uid -> new Queue[Vector2D])
+ else {
+ prevPos(s.uid).enqueue(s.pos)
+ for(i <- 0 until prevPos(s.uid).length - 1) {
+ val sp = prevPos(s.uid)(i)
+ val ep = prevPos(s.uid)(i + 1)
+ s.g.setColor(java.awt.Color.cyan)
+ s.drawLine(sp, ep)
+ }
+ if (prevPos(s.uid).length == 50) prevPos(s.uid).dequeue
+ }
+ }
+ }
+
+ def getBody(p: Vector2D): Option[Body] = {
+ val shape = scene.shapes.find(_.contains(p))
+ if (shape != None) Some(shape.get.real.body)
+ else None
+ }
+
+ var mousePressed: Boolean = false
+ var startPoint = new java.awt.Point(0,0)
+ var endPoint = new java.awt.Point(0,0)
+ var grabbedBody: Option[GrabbedBody] = None
+ def grab(b: Body, p: Vector2D) = {
+ grabbedBody = Some(new GrabbedBody(b, p))
+ b.fixed = true
+ }
+
+ def release() = {
+ if (grabbedBody != None && grabbedBody.get.wasFixed == false)
+ grabbedBody.get.body.fixed = false
+ grabbedBody = None
+ }
+
+ listenTo(mouse.clicks, mouse.moves, mouse.wheel)
+ reactions += {
+ case MousePressed(c,p,x,y,b) => {
+ mousePressed = true; startPoint = p; endPoint = p
+ x match {
+ case 1024 if (getBody(p) != None) => grab(getBody(p).get, p)
+ case 1152 if (getBody(p) != None) => {grabbedBody = Some(new GrabbedBody(getBody(p).get, p)); popup.body = grabbedBody.get.body; popup.peer.setLocation(p); popup.visible = true}
+ case 4096 if (getBody(p) != None) => {grabbedBody = Some(new GrabbedBody(getBody(p).get, p)); popup.body = grabbedBody.get.body; popup.peer.setLocation(p); popup.visible = true}
+ case _ => ()
+ }
+ }
+
+ case MouseMoved(c,p,i) => {
+ lblBody.text = (if (getBody(p) != None) getBody(p).get.uid.toString else "None") + " @ (" + point2Vector(p).x.formatted("%f") + ", " + point2Vector(p).y.formatted("%f") + ")"
+ }
+
+ case MouseDragged(c,p,1088) => {//drag with shift
+ offset += Vector2D((p.x - endPoint.x), -(p.y - endPoint.y))
+ mousePressed = true
+ endPoint = p
+ cursor = new java.awt.Cursor(java.awt.Cursor.MOVE_CURSOR)
+ }
+
+ case MouseDragged(c,p,x) =>
+ if (grabbedBody != None) grabbedBody.get.body.pos = p - grabbedBody.get.r
+
+ case MouseReleased(c,p,x,y,b) => {
+ mousePressed = false
+ endPoint = p
+ cursor = new java.awt.Cursor(java.awt.Cursor.CROSSHAIR_CURSOR)
+ release()
+ }
+
+ case MouseWheelMoved(c,p,1024,y) => { //with left mouse button pressed
+ if (grabbedBody != None) grabbedBody.get.body.rotation += 0.05 * y
+ }
+
+ case MouseWheelMoved(c,p,x,y) => {
+ scale -= scale * 0.02 * y
+ }
+
+ }
+}
+
+class GrabbedBody(b: Body, point: Vector2D){
+ def body = b
+ val r: Vector2D = point - body.pos
+ val wasFixed = b.fixed
+}