All Downloads are FREE. Search and download functionalities are using the official Maven repository.

doodle.java2d.effect.Java2dWindow.scala Maven / Gradle / Ivy

/*
 * Copyright 2015 Creative Scala
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package doodle.java2d.effect

import doodle.core.Point
import doodle.java2d.Picture
import doodle.java2d.effect.Size.FixedSize

import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import java.awt.event.WindowAdapter
import java.awt.event.WindowEvent
import java.util.concurrent.CompletableFuture
import javax.swing.JFrame
import javax.swing.SwingUtilities
import javax.swing.Timer
import javax.swing.WindowConstants
import scala.concurrent.duration.FiniteDuration

/** Create a GUI window (a Frame in Swing parlance) around a Java2dPanel. */
final class Java2dWindow(
    frame: Frame,
    frameDelay: FiniteDuration,
    redrawQueue: BlockingCircularQueue[Int],
    mouseClickQueue: BlockingCircularQueue[Point],
    mouseMoveQueue: BlockingCircularQueue[Point]
) extends JFrame(frame.title) {
  def render[A](picture: Picture[A]): CompletableFuture[A] =
    panel.render(picture)

  /** This `CompletedFuture` is completed when this `Java2dWindow` is closed. */
  val closed: CompletableFuture[Boolean] = CompletableFuture()

  // Only call from within the event thread
  private def internalClose(): Unit = {
    timer.stop()
    dispose()
    closed.complete(true)
    ()
  }

  def close(): CompletableFuture[Boolean] = {
    SwingUtilities.invokeAndWait(() => internalClose())
    closed
  }

  val panel = Java2DPanel(frame, mouseClickQueue, mouseMoveQueue)

  /** Event listener for redraw events. Translates events into the time since
    * the last frame (TODO: what are the units)?
    */
  private val frameEvent = {

    /** Delay between frames when rendering at 60fps */
    var firstFrame = true
    var lastFrameTime = 0L
    new ActionListener {
      def actionPerformed(e: ActionEvent): Unit = {
        val now = e.getWhen()
        if firstFrame then {
          firstFrame = false
          lastFrameTime = now
          redrawQueue.add(0)
          ()
        } else {
          redrawQueue.add((now - lastFrameTime).toInt)
          lastFrameTime = now
        }
      }
    }
  }

  /** Timer that ticks every frameDelay */
  private val timer = new Timer(frameDelay.toMillis.toInt, frameEvent)
  this.addWindowListener(
    new WindowAdapter {
      override def windowClosed(evt: WindowEvent): Unit = {
        internalClose()
        ()
      }
    }
  )

  getContentPane().add(panel)
  frame.size match {
    case FixedSize(width, height) =>
      setSize(width.toInt, height.toInt)
    case _ => ()
  }
  pack()
  setVisible(true)
  setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)
  repaint()
  timer.start()

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy