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

scalafx.event.EventHandler.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2011-2014, ScalaFX Project
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the ScalaFX Project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE SCALAFX PROJECT OR ITS CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package scalafx.event

import javafx.{event => jfxe}

import scala.language.{implicitConversions, reflectiveCalls}
import scalafx.delegate.SFXDelegate
import scalafx.event.subscriptions.Subscription

/**
 * Companion Object for [[http://docs.oracle.com/javase/8/javafx/api/javafx/event/EventHandler.html EventHandler]]
 * interface.
 */
object EventHandler {
}

/**
 * Trait used for handle events manipulation. JavaFX class wrapped must have methods defined in
 * [[scalafx.event.EventHandlerDelegate.EventHandled]] Type:
 * {{{
 * def addEventHandler   [E <: jfxe.Event](eventType: jfxe.EventType[E], eventHandler: jfxe.EventHandler[_ >: E])
 * def removeEventHandler[E <: jfxe.Event](eventType: jfxe.EventType[E], eventHandler: jfxe.EventHandler[_ >: E])
 * def addEventFilter    [E <: jfxe.Event](eventType: jfxe.EventType[E], eventHandler: jfxe.EventHandler[_ >: E])
 * def removeEventFilter [E <: jfxe.Event](eventType: jfxe.EventType[E], eventHandler: jfxe.EventHandler[_ >: E])
 * def buildEventDispatchChain(chain: jfxe.EventDispatchChain): jfxe.EventDispatchChain
 * }}}
 */
trait EventHandlerDelegate {

  /**
   *
   */
  type EventHandled = {
    // Registers an event handler to this type.
    def addEventHandler[E <: jfxe.Event](eventType: jfxe.EventType[E], eventHandler: jfxe.EventHandler[_])

    // Unregisters a previously registered event handler from this type.
    def removeEventHandler[E <: jfxe.Event](eventType: jfxe.EventType[E], eventHandler: jfxe.EventHandler[_])

    // Registers an event filter to this type.
    def addEventFilter[E <: jfxe.Event](eventType: jfxe.EventType[E], eventHandler: jfxe.EventHandler[_])

    // Unregisters a previously registered event filter from this type.
    def removeEventFilter[E <: jfxe.Event](eventType: jfxe.EventType[E], eventHandler: jfxe.EventHandler[_])

    // Construct an event dispatch chain for this target.
    def buildEventDispatchChain(chain: jfxe.EventDispatchChain): jfxe.EventDispatchChain
  }

  /**
   * Returns a object that implements [[scalafx.event.EventHandlerDelegate.EventHandled]].
   */
  protected def eventHandlerDelegate: EventHandled

  /**
   * Registers an event handler to this task. Any event filters are first processed, then the
   * specified onFoo event handlers, and finally any event handlers registered by this method.
   * As with other events in the scene graph, if an event is consumed, it will not continue
   * dispatching.
   *
   * @tparam E Event class
   * @param eventType  the type of the events to receive by the handler
   * @param eventHandler the handler to register that will manipulate event
   */
  def addEventHandler[E <: jfxe.Event](eventType: jfxe.EventType[E], eventHandler: jfxe.EventHandler[_ >: E]) {
    eventHandlerDelegate.addEventHandler(eventType, eventHandler)
  }


  /**
   * Trait implementing [[http://spray.io/blog/2012-12-13-the-magnet-pattern/ Magnet Pattern]]
   * to avoid compilation error "ambiguous reference to overloaded definition"
   */
  sealed trait HandlerMagnet[J <: jfxe.Event, S <: SFXDelegate[J]] {
    protected val eventHandler: jfxe.EventHandler[J]

    def apply(eventType: EventType[J]): Subscription = {
      EventHandlerDelegate.this.addEventHandler(eventType.delegate, eventHandler)
      new Subscription {
        def cancel() {
          EventHandlerDelegate.this.removeEventHandler(eventType.delegate, eventHandler)
        }
      }
    }
  }

  /**
   * Companion object implementing Magnet Pattern [[http://spray.io/blog/2012-12-13-the-magnet-pattern/ Magnet Pattern]]
   * to avoid compilation error "ambiguous reference to overloaded definition"
   */
  object HandlerMagnet {
    implicit def fromParen[J <: jfxe.Event, S <: Event with SFXDelegate[J]](op: () => Unit): HandlerMagnet[J, S] = {
      new HandlerMagnet[J, S] {
        override val eventHandler = new jfxe.EventHandler[J] {
          def handle(event: J) {
            op()
          }
        }
      }
    }

    implicit def fromEvent[J <: jfxe.Event, S <: Event with SFXDelegate[J]](op: S => Unit)(implicit jfx2sfx: J => S): HandlerMagnet[J, S] = {
      new HandlerMagnet[J, S] {
        override val eventHandler = new jfxe.EventHandler[J] {
          def handle(event: J) {
            op(jfx2sfx(event))
          }
        }
      }
    }
  }

  /**
   * Registers an event handler. The handler is called when the node receives an Event of the specified type during the bubbling phase of event delivery.
   *
   * Example of handling mouse events
   * {{{
   *  pane.handleEvent(MouseEvent.Any) {
   *    me: MouseEvent => {
   *      me.eventType match {
   *        case MouseEvent.MousePressed => ...
   *        case MouseEvent.MouseDragged => ...
   *        case _                       => {}
   *      }
   *    }
   *  }
   * }}}
   * or
   * {{{
   *  pane.handleEvent(MouseEvent.Any) { () => println("Some mouse event handled") }
   * }}}
   *
   * @param eventType type of events that will be handled.
   * @param handler code handling the event, see examples above.
   * @tparam J type JavaFX delegate of the event
   * @tparam S ScalaFX type for `J` type wrapper.
   * @return Returns a subscription that can be used to cancel/remove this event handler
   */
  def handleEvent[J <: jfxe.Event, S <: Event with SFXDelegate[J]](eventType: EventType[J])(handler: HandlerMagnet[J, S]): Subscription = {
    handler(eventType)
  }


  /**
   * Unregisters a previously registered event handler from this task. One handler might have been
   * registered for different event types, so the caller needs to specify the particular event type
   * from which to unregister the handler.
   *
   * @tparam E Event class
   * @param eventType  the event type from which to unregister
   * @param eventHandler  the handler to unregister
   */
  def removeEventHandler[E <: jfxe.Event](eventType: jfxe.EventType[E], eventHandler: jfxe.EventHandler[_ >: E]) {
    eventHandlerDelegate.removeEventHandler(eventType, eventHandler)
  }

  /**
   * Registers an event filter to this task. Registered event filters get an event before any
   * associated event handlers.
   *
   * @tparam E Event class
   * @param eventType  the type of the events to receive by the filter
   * @param eventHandler the filter to register that will filter event
   */
  def addEventFilter[E <: jfxe.Event](eventType: jfxe.EventType[E], eventHandler: jfxe.EventHandler[_ >: E]) {
    eventHandlerDelegate.addEventFilter(eventType, eventHandler)
  }

  /**
   * Trait implementing [[http://spray.io/blog/2012-12-13-the-magnet-pattern/ Magnet Pattern]]
   * to avoid compilation error "ambiguous reference to overloaded definition"
   */
  sealed trait FilterMagnet[J <: jfxe.Event, S <: SFXDelegate[J]] {
    protected val eventFilter: jfxe.EventHandler[J]

    def apply(eventType: EventType[J]): Subscription = {
      EventHandlerDelegate.this.addEventFilter(eventType.delegate, eventFilter)
      new Subscription {
        def cancel() {
          EventHandlerDelegate.this.removeEventFilter(eventType.delegate, eventFilter)
        }
      }
    }
  }

  /**
   * Companion object implementing Magnet Pattern [[http://spray.io/blog/2012-12-13-the-magnet-pattern/ Magnet Pattern]]
   * to avoid compilation error "ambiguous reference to overloaded definition"
   */
  object FilterMagnet {
    implicit def fromParen[J <: jfxe.Event, S <: Event with SFXDelegate[J]](op: () => Unit): FilterMagnet[J, S] = {
      new FilterMagnet[J, S] {
        override val eventFilter = new jfxe.EventHandler[J] {
          def handle(event: J) {
            op()
          }
        }
      }
    }

    implicit def fromEvent[J <: jfxe.Event, S <: Event with SFXDelegate[J]](op: S => Unit)(implicit jfx2sfx: J => S): FilterMagnet[J, S] = {
      new FilterMagnet[J, S] {
        override val eventFilter = new jfxe.EventHandler[J] {
          def handle(event: J) {
            op(jfx2sfx(event))
          }
        }
      }
    }
  }

  /**
   * Registers an event filter. Registered event filters get an event before any associated event handlers.
   *
   * Example of filtering mouse events
   * {{{
   *  pane.filterEvent(MouseEvent.Any) {
   *    me: MouseEvent => {
   *      me.eventType match {
   *        case MouseEvent.MousePressed => {
   *          ...
   *        }
   *        case MouseEvent.MouseDragged => {
   *          ...
   *        }
   *        case _ => {
   *          ...
   *        }
   *      }
   *    }
   *  }
   * }}}
   * or
   * {{{
   *  pane.filterEvent(MouseEvent.Any) { () => println("Some mouse event handled") }
   * }}}
   *
   * @param eventType type of events that will be handled.
   * @param filter code handling the event, see examples above.
   * @tparam J type JavaFX delegate of the event
   * @tparam S ScalaFX type for `J` type wrapper.
   */
  def filterEvent[J <: jfxe.Event, S <: Event with SFXDelegate[J]](eventType: EventType[J])(
    filter: FilterMagnet[J, S]): Subscription = {
    filter(eventType)
  }

  /**
   * Unregisters a previously registered event filter from this task. One filter might have been
   * registered for different event types, so the caller needs to specify the particular event
   * type from which to unregister the filter.
   *
   * @tparam E Event class
   * @param eventType the event type from which to unregister
   * @param eventHandler the filter to unregister
   */
  def removeEventFilter[E <: jfxe.Event](eventType: jfxe.EventType[E], eventHandler: jfxe.EventHandler[_ >: E]) {
    eventHandlerDelegate.removeEventFilter(eventType, eventHandler)
  }

  /**
   * Construct an event dispatch chain for this target.
   */
  def buildEventDispatchChain(chain: jfxe.EventDispatchChain) = eventHandlerDelegate.buildEventDispatchChain(chain)

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy