Calico Events

From IPRE Wiki
Jump to: navigation, search

The Events module is used for broadcasting and receiving messages/events. Here, we call broadcast "publish", and we call receive "subscribe". You can use these functions to create sophisticated event-driven programming. This allows code to run in parallel, or to sequence sections of code.

The following examples use Python's syntax, but you can use any Calico language.

Initialization

To use the Events system, you need to initialize it:

import Events
Events.init()

This is also used to reset the events system. If you need to clear out all subscriptions, just issue Events.init() again.

Subscribe

To listen for a message, you need to subscribe to it. For each subscription, you will associate a function. Each of these functions will receive an object (which could be None) and an Event when the message is published.

  • Events.subscribe(message, function) - run the function when message is received
  • Events.subscribe(message, function, object) - run the function when message is received for object
  • Events.subscribe(message, function, object, calico) - same as above, but pass in the Calico: calico object reference in case you need it in function
  • Events.subscribe(calico, message, function) - same as above, with no object
import Events
Events.init()

def mycode(object, event):
    print("Message received!")

Events.subscribe("my message", mycode)
Events.publish("my message")

The above code creates a subscriber such that when the message "my message" is received, it will run the code in the mycode function.

All of the subscribe functions return an ID. You can use the ID to unsubscribe the subscription:

id = Events.subscribe("message", function)
Events.unsubscribe(id)

This would remove the event handler for "message" and function would not run.

You can reuse the same functions for multiple subscriptions. If you do, you can look at object to see which associated object is used, or look at the Event to see which event it is handing.

NOTE: the system doesn't do anything itself to keep the user from causing an event to run repeatedly. For example, clicking on a shape over and over will "fire" the associated code again and again, perhaps even before it has completed the first time.

If an object is subscribed to "my message" then it will receive all such messages published to the object. In addition, it also receives "my message" published without a specific object. For example:

import Events
from Myro import wait
Events.init()

import threading
lock = threading.Lock()

def wrap(f):
    def inner(o, e):
        lock.acquire()
        f(o, e)
        lock.release()
    return inner

@wrap
def mycode(object, event):
    print("Message received for", object, event)

Events.subscribe("my message", mycode, "myobject1")
Events.subscribe("my message", mycode, "myobject2")

Events.publish("my message", "myobject1")
wait(1)
Events.publish("my message", "myobject2")
wait(1)
Events.publish("my message")

This code would result in something similar to:

Message received for myobject1 <Event "my message" at 1375709643.1> # first message
Message received for myobject2 <Event "my message" at 1375709644.2> # second message
Message received for myobject1 <Event "my message" at 1375709645.3> # third message
Message received for myobject2 <Event "my message" at 1375709645.3> # third message

That is:

  1. "myobject1" receives a message intended just for it.
  2. "myobject2" receives a message intended just for it.
  3. "myobject1" and "myobject2" both receive the general message.

All code that receives a message through a subscription will run in the background.

Publish

Messages can be published stand-alone, or from a particular object.

  • Events.publish(message) - publish a message for all subscribers
  • Events.publish(message, object) - publish a message for a particular object's subscription
  • Events.publish(Event) - publish an Event object for Event.obj's subscription
  • Events.publish(calico, message) - publish a message via the chat system for all
  • Events.publish(calico, message, to) - publish a message via the chat system for a particular user

The following publish commands will send a message or event, but waits until all associated subscribed code has completed before returning:

  • Events.publishAndWait(message) - publish a message for all subscribers
  • Events.publishAndWait(message, object) - publish a message for a particular object's subscription
  • Events.publishAndWait(Event) - publish an Event object for Event.obj's subscription

Another way to describe these functions is that they 'block' until all of the associated code is completed. This might be a way to create a point in time where all of the code must wait until completion before continuing.

Graphics

You can subscribe any shape from the Calico Graphics library to any message, and also a number of special messages:

  • "key-press"
  • "key-release"
  • "mouse-motion"
  • "mouse-press"
  • "mouse-release"
from Graphics import *
import Events
Events.init()

win = Window()
sprite = Sprite("bear")
sprite.drawAt(win, (150, 150))

def mousepress(o, e):
    sprite.flipToNextFrame()

sprite.subscribe("mouse-press", mousepress)

This would make it so that when you click on the bear sprite, it will change to the next frame in the animation.

NOTE: when you press and hold down a key, it repeatedly publishes a "key-press" event every few milliseconds. All of the other mouse and key events only occur once per action.

Event Object

The subscribed code will receive an Event object. These objects have the following properties:

  • time - indicates the time the event occurred (eg, when it was clicked)
  • type - the associated message
  • wait - is this a publish and wait event?
  • obj - the associated object (if one)
  • x - the x location of the event
  • y - the y location of the event
  • key - the keycode of the key event
  • value - value to be returned to the publishAndWait call

You can make your own events to publish.

Internal Functions

The following are internal functions and would not normally be called directly.

  • Events.getID(object, message) - gets the ID for the object+message combination.
  • Events.loop() - start the event-handling loop in the background
  • Events.stop() - stop the event-handling loop