Commit 0ae37930 authored by h2b's avatar h2b

Event handling changed to event bus classified by screen.

parent fba54458
......@@ -19,29 +19,36 @@ package de.h2b.scala.lib.simgraf.driver
import java.awt.Color
import java.awt.event.{ KeyEvent AwtKeyEvent, KeyListener AwtKeyListener,
MouseEvent AwtMouseEvent, MouseListener AwtMouseListener,
MouseMotionListener AwtMouseMotionListener,
MouseWheelEvent AwtMouseWheelEvent,
MouseWheelListener AwtMouseWheelListener }
MouseEvent AwtMouseEvent, MouseListener AwtMouseListener,
MouseMotionListener AwtMouseMotionListener,
MouseWheelEvent AwtMouseWheelEvent,
MouseWheelListener AwtMouseWheelListener }
import de.h2b.scala.lib.simgraf.Pixel
import akka.actor.Props
import de.h2b.scala.lib.simgraf.{ Pixel, Screen }
import de.h2b.scala.lib.simgraf.event.{ AltGraphModifier, AltModifier, Button,
CtrlModifier, DragEvent, KeyEvent, LeftButton, MetaModifier, MiddleButton,
Modifier, MouseEvent, NoButton, OtherButton, RightButton, ShiftModifier,
WheelEvent, publisher }
CtrlModifier, DragEvent, KeyEvent, LeftButton, MetaModifier, MiddleButton,
Modifier, MouseEvent, NoButton, OtherButton, Publisher, RightButton,
ShiftModifier, WheelEvent, system }
import javax.swing.SwingUtilities
/**
* Provides key and mouse listeners publishing key and mouse events to the
* event-package publisher.
*
* @note As of version 1.3.0, this trait can only be mixed into a class that is
* a subtype of `Screen`, which is required now and was the intention from the
* beginning.
*
* @since 1.2.0
* @author h2b
*/
trait AwtEventDriver extends AwtScreenDriver {
trait AwtEventDriver extends AwtScreenDriver { self: Screen
import AwtEventDriver._
private val publisher = system.actorOf(Props(new Publisher(Some(self))))
panel.addKeyListener(KeyListener)
panel.addMouseListener(MouseListener)
panel.addMouseMotionListener(MouseListener)
......
......@@ -176,6 +176,10 @@ abstract class ScreenDriver protected (val p0: Pixel, val width: Int, val height
}
/**
* @note As of version 1.3.0, factory methods have been removed, since screen
* required now.
*/
object ScreenDriver {
/** screen origin **/
......@@ -185,58 +189,4 @@ object ScreenDriver {
/** available screen width in pixels */
val screenWidth: Int = AwtScreenDriver.screenWidth
/**
* @param p0 location of the upper-left corner on the screen
* @param width horizontal dimension
* @param height vertical dimension
* @param title optional window title (will not reduce the drawing area,
* defaults to empty string)
* @return a new default screen driver
*/
def apply (p0: Pixel, width: Int, height: Int, title: String = ""): ScreenDriver =
awt(p0, width, height, title)
/**
* @param cell defines location, width and height of this screen driver
* @param title window title (will not reduce the drawing area)
* @return a new default screen driver
*/
def apply (cell: Cell, title: String): ScreenDriver =
apply(cell.origin, cell.width, cell.height, title)
/**
* @param cell defines location, width and height of this screen driver
* @param title window title (will not reduce the drawing area)
* @return a new default screen driver with some input events enabled
*/
def withEvents (cell: Cell, title: String): ScreenDriver =
awtWithEvents(cell, title)
/**
* @param p0 location of the upper-left corner on the screen
* @param width horizontal dimension
* @param height vertical dimension
* @param title optional window title (will not reduce the drawing area,
* defaults to empty string)
* @return a new AWT screen driver
*/
def awt (p0: Pixel, width: Int, height: Int, title: String = ""): ScreenDriver =
new ScreenDriver(p0, width, height, title) with AwtScreenDriver
/**
* @param cell defines location, width and height of this screen driver
* @param title window title (will not reduce the drawing area)
* @return a new AWT screen driver
*/
def awt (cell: Cell, title: String): ScreenDriver =
awt(cell.origin, cell.width, cell.height, title)
/**
* @param cell defines location, width and height of this screen driver
* @param title window title (will not reduce the drawing area)
* @return a new AWT screen driver with key and mouse events enabled
*/
def awtWithEvents (cell: Cell, title: String): ScreenDriver =
new ScreenDriver(cell.origin, cell.width, cell.height, title) with AwtEventDriver
}
......@@ -18,6 +18,7 @@
package de.h2b.scala.lib.simgraf.event
import akka.actor.Actor
import de.h2b.scala.lib.simgraf.Screen
import de.h2b.scala.lib.util.{ Level, Logger }
/**
......@@ -26,15 +27,19 @@ import de.h2b.scala.lib.util.{ Level, Logger }
*
* @since 1.2.0
* @author h2b
*
* @constructor
*
* @param screen optional classifier
*/
class Publisher extends Actor {
class Publisher (screen: Option[Screen] = None) extends Actor {
private val log = Logger(getClass) at Level.Warn
def receive = {
case e: Event
log.debug(s"event received: $e")
stream.publish(e)
stream.publish(e screen)
case unknown
log.warn(s"unknown message received: $unknown")
}
......
/*
SimGraf - A Simple Scala Graphics Library
Copyright 2016-2017 Hans-Hermann Bode
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 de.h2b.scala.lib.simgraf.event
import akka.event.{ ActorEventBus, EventBus, LookupClassification }
import de.h2b.scala.lib.simgraf.Screen
/**
* An event bus for events classified by screen.
*
* @since 1.3.0
* @author h2b
*/
object ScreenEventBus extends EventBus with LookupClassification
with ActorEventBus {
type Event = ClassifiedEvent
type Classifier = Option[Screen]
override def mapSize: Int = 2
override def classify (event: Event): Classifier = event._2
override protected def publish (event: Event, subscriber: Subscriber): Unit =
subscriber ! event._1
}
......@@ -18,6 +18,7 @@
package de.h2b.scala.lib.simgraf.event
import akka.actor.{ Actor, ActorRef, Props }
import de.h2b.scala.lib.simgraf.{ Screen, World }
import de.h2b.scala.lib.util.{ Level, Logger }
/**
......@@ -27,9 +28,10 @@ import de.h2b.scala.lib.util.{ Level, Logger }
* @since 1.2.0
* @author h2b
*/
class Subscriber private (val handler: PartialFunction[Event, Unit]) extends Actor {
class Subscriber private (screen: Option[Screen])
(val handler: PartialFunction[Event, Unit]) extends Actor {
override def preStart = stream.subscribe(self, classOf[Event])
override def preStart = stream.subscribe(self, screen)
private val log = Logger(getClass) at Level.Warn
......@@ -46,10 +48,36 @@ class Subscriber private (val handler: PartialFunction[Event, Unit]) extends Act
object Subscriber {
/**
* Subscribes to events not associated with a screen.
*
* @param handler partial function handling received events
* @return a reference to a new subscriber
*/
def ref (handler: PartialFunction[Event, Unit]): ActorRef =
system.actorOf(Props(new Subscriber(handler)))
system.actorOf(Props(new Subscriber(None)(handler)))
/**
* Subscribes to events of a specified screen.
*
* @param screen the screen to be listened for events
* @param handler partial function handling received events
* @return a reference to a new subscriber
*
* @since 1.3.0
*/
def on (screen: Screen) (handler: PartialFunction[Event, Unit]): ActorRef =
system.actorOf(Props(new Subscriber(Some(screen))(handler)))
/**
* Subscribes to events of a specified screen.
*
* @param world the world to be listened for events
* @param handler partial function handling received events
* @return a reference to a new subscriber
*
* @since 1.3.0
*/
def on (world: World) (handler: PartialFunction[Event, Unit]): ActorRef =
on(world.screen)(handler)
}
......@@ -18,6 +18,7 @@
package de.h2b.scala.lib.simgraf
import akka.actor.{ ActorSystem, Props }
import akka.event.EventBus
/**
* This package constitutes a high-level abstraction of input (e.g.,
......@@ -50,6 +51,12 @@ import akka.actor.{ ActorSystem, Props }
*/
package object event {
/**
* An event optionally associated with a screen.
* @since 1.3.0
*/
type ClassifiedEvent = (Event, Option[Screen])
/** The actor system used in this package. */
val system = ActorSystem("SimGraf")
......@@ -57,13 +64,20 @@ package object event {
* The event stream global to this package.
*
* Subscribe to this stream to retrieve triggered events.
*
* @note As of version 1.3.0, the definition changed from `EventStream` to
* `ScreenEventBus` (both are implementations of `EventBus`) in order to
* handle events classified by screen.
*/
val stream = system.eventStream
val stream = ScreenEventBus
/**
* The actor publishing all events to the global event stream that are
* triggered by drivers.
* The actor publishing events to the global event stream that are triggered
* by drivers and are not associated with a screen.
*
* @note As of version 1.3.0, the definition changed from ''all events'' to
* ''events not associated with a screen''.
*/
val publisher = system.actorOf(Props[Publisher])
val publisher = system.actorOf(Props(new Publisher(None)))
}
......@@ -35,7 +35,7 @@ object EventEchoDemo extends App {
case Point(x, y) if (x<0 && y<0) Color.White
case _ Color.Red
}))
Subscriber.ref {
Subscriber.on(world) {
case KeyEvent(k) if k=='q'
world.screen.close()
system.terminate()
......
......@@ -22,6 +22,9 @@ import scala.util.Random
import de.h2b.scala.lib.simgraf.{ Color, Pixel }
import de.h2b.scala.lib.simgraf.driver.ScreenDriver
import de.h2b.scala.lib.simgraf.layout.GridLayout
import de.h2b.scala.lib.simgraf.Screen
import de.h2b.scala.lib.simgraf.driver.AwtScreenDriver
import de.h2b.scala.lib.simgraf.layout.Cell
object ScreenDriverDemo extends App {
......@@ -31,21 +34,24 @@ object ScreenDriverDemo extends App {
private val iterator = GridLayout.onScreen(2, 3).iterator
private def next () = iterator.next().fit(w, h)
private val driver1 = ScreenDriver(next(), "Screen Driver Demo 1")
private def driver (cell: Cell, title: String): ScreenDriver =
new ScreenDriver(cell.origin, cell.width, cell.height, title) with AwtScreenDriver
private val driver1 = driver(next(), "Screen Driver Demo 1")
drawGrid(driver1)
driver1.activeColor = Color.Blue
driver1.drawLine(Pixel(0,0), Pixel(w,h))
driver1.activeColor = Color.Red
driver1.drawLine(Pixel(0,h), Pixel(w,0))
private val driver2 = ScreenDriver(next(), "Screen Driver Demo 2")
private val driver2 = driver(next(), "Screen Driver Demo 2")
drawGrid(driver2)
driver2.activeColor = Color.Blue
driver2.fillRectangle(Pixel(50,50), Pixel(w-50,h-50))
driver2.activeColor = Color.Red
driver2.drawRectangle(Pixel(50,50), Pixel(w-50,h-50))
private val driver3 = ScreenDriver(next(), "Screen Driver Demo 3")
private val driver3 = driver(next(), "Screen Driver Demo 3")
drawGrid(driver3)
val poly3 = Seq(Pixel(50,50), Pixel(w-50,50), Pixel(w/2,h-50), Pixel(50,50))
driver3.activeColor = Color.Blue
......@@ -53,7 +59,7 @@ object ScreenDriverDemo extends App {
driver3.activeColor = Color.Red
driver3.drawPolyline(poly3)
private val driver4 = ScreenDriver(next(), "Screen Driver Demo 4")
private val driver4 = driver(next(), "Screen Driver Demo 4")
drawGrid(driver4)
driver4.activeColor = Color.Blue
driver4.fillArc(Pixel(w/2,h/2), w-100, h-100, 0, 90)
......@@ -62,7 +68,7 @@ object ScreenDriverDemo extends App {
driver4.activeColor = Color.Red
driver4.drawArc(Pixel(w/2,h/2), w-100, h-100, 0, 360)
private val driver5 = ScreenDriver(next(), "Screen Driver Demo 5")
private val driver5 = driver(next(), "Screen Driver Demo 5")
for {
x 0 to w
y 0 to h
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment