This document is only applicable for Guichan 0.7.0 and upwards, however most part of the document also applies for Guichan 0.6.0.

Events

Guichan comes with a sophisticated event system much like the event system found in Java. Events are very important to understand in order to fully be able to use Guichan.

The event hierarchy

All events in Guichan is a part of the event hierarchy which is made of a couple of classes presented below:

Event structure

Where Event is the base class, ActionEvent represents an action event triggered by a widget, InputEvent represents an input event, KeyEvent represents a key input event, MouseEvent represents a mouse input event and FocusEvent represents a focus event.

Receiving events

To be able to receive events one must implement a listener which listens for a certain type of event. In Guichan there exists a listener interface for each type of event which can be received. All events concerns a widget and all that is required to receive events concerning a widget is to add an implemented listener to the widget. As soon as an event is fired all listeners of the widget will be notifed.

A widget can listen for events which concerns the widget itself, this is how most widgets in Guichan is implemented, a button for instance implements the MouseListener interface and listens for mouse events on itself. How to implement a listener for a certain type of event and how the event is distributed is explained later on.

Basic events

All events derives from the Event base class. How events are distributed and when they are distributed depends on the event type, but all events have a widget in common called the source widget which is the widget the event concerns. All events can get the source widget by calling the Event::getSource function.

void MyCustomWidget::action(const ActionEvent& actionEvent)
{
    Widget* sourceWidget = actionEvent.getSource();
}
An example of using Event::getSource with an ActionEvent.

Input events

Input events are events which concerns input. The input is either key input or mouse input. All input events are consumable. However, if an input event is consumed it's merely marked as consumed, it's up the receiver of the event to take a different action if an event has been consumed (this is going to be illustrated later on when discussing mouse input).

To consume an input event the InputEvent::consume function is used. To check if an input event has been consumed the InputEvent::isConsumed is used.

void MyCustomWidget::mouseWheelMovedDown(MouseEvent& mouseEvent)
{
    mouseEvent.consume();
}
An example of using InputEvent::consume with a MouseEvent.

Key events

Key events are events which concerns key input. They fire as soon as key input is received by Guichan and will always have the widget with focus as the source widget. Key events are only distributed to the key listeners of the source widget.

Recieving key events

To receive key events one must implement the KeyListener interface.

#include <guichan.hpp>
#include <iostream>

class MyKeyListener : public gcn::KeyListener
{
    void keyPressed(gcn::KeyEvent& keyEvent)
    {
        std::cout << "Key pressed: " << keyEvent.getKey().getValue() << std::endl;
    }
   
    void keyReleased(gcn::KeyEvent& keyEvent)
    {
        std::cout << "Key released: " << keyEvent.getKey().getValue() << std::endl;
    }
};
An example of an implemented key listener which prints the key values pressed and released.

To receive key events from a button add the implementation as a key listener of a button.

MyKeyListener myKeyListener;
gcn::Button button;

void foo()
{
    button.addKeyListener(&keyListener);
}
An example of adding a key listener to a button.

Most implemented widgets in Guichan which uses key input are key listeners themselves and listen for key events on themselves.

#include <guichan.hpp>
#include <iostream>

class MyCustomWidget: public gcn::Widget, public gcn::KeyListener
{
public:
    MyCustomWidget()
    {
        // The widget needs to be focusable in order to receive key events.
        setFocusable(true);
        addKeyListener(this);
    }     

    void keyPressed(gcn::KeyEvent& keyEvent)
    {
        std::cout << "Key pressed: " << keyEvent.getKey().getValue() << std::endl;
    }
   
    void keyReleased(gcn::KeyEvent& keyEvent)
    {
        std::cout << "Key released: " << keyEvent.getKey().getValue() << std::endl;
    }
};
An example of a widget which is only capable of printing key events.

Mouse events

Mouse events are events which concerns mouse input. They fire as soon as mouse input is received by Guichan. Mouse events are distributed to the mouse listeners of the widget directly under the mouse and to the mouse listeners of the parents of the widget directly under the mouse.

For instance, concider the case where a button is placed in a window and the window is placed in a container. If the button is pressed with the mouse all mouse listeners of the button will receive the mouse press followed by all mouse listeners of the window and finally followed by all mouse listeners of the container. Note that the source of the event will always be the widget directly under the mouse, in this case the button, even if other widget mouse listeners receive the event, such as the mouse listeners of the window and the container.

Mouse events always travels upwards in the placement hierarchy, a bottom up approuch. The reason for this is that if a widget, like the button, is pressed with the mouse the widget's container, like the window, is also pressed and should also receive the mouse event.

There exists one exception to the bottom up distribution and that is mouse entered and mouse exited events, they are only - like key events - distributed to the mouse listeners of the source widget of the event, in this case to the mouse listeners of the widget directy under the mouse.

Chain of responsibility

The design of bottom up distribution introduces a chain of responsibility. If a widget needs to consume an input, like a slider wants to consume mouse wheel events, widgets acting on the same event, such as a scroll area, should discard the input if it has been consumed.

Recieving mouse events

To receive mouse events one must implement a mouse listener.

#include <guichan.hpp>
#include <iostream>

class MyMouseListener : public gcn::MouseListener
{
    void mousePressed(gcn::MouseEvent& mouseEvent)
    {
        std::cout << "Mouse pressed: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl;
    }
   
    void mouseReleased(gcn::MouseEvent& mouseEvent)
    {  
        std::cout << "Mouse pressed: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl;
    }

    void mouseClicked(gcn::MouseEvent& mouseEvent)
    {  
        std::cout << "Mouse clicked: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl;
    }

    void mouseMoved(gcn::MouseEvent& mouseEvent)
    {  
        std::cout << "Mouse moved: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl;
    }

    void mouseEntered(gcn::MouseEvent& mouseEvent)
    {  
        std::cout << "Mouse entered: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl;
    }

    void mouseExited(gcn::MouseEvent& mouseEvent)
    {  
        std::cout << "Mouse exited: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl;
    }

    void mouseWheelMovedDown(gcn::MouseEvent& mouseEvent)
    {  
        std::cout << "Mouse wheel down moved: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl;
    }

    void mouseWheelMovedUp(gcn::MouseEvent& mouseEvent)
    {  
        std::cout << "Mouse wheel up moved: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl;
    }

    void mouseDragged(gcn::MouseEvent& mouseEvent)
    {  
        std::cout << "Mouse dragged: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl;
    }
};
An example of an implemented mouse listener which prints the x and y coordinate of the mouse event. The coordinates are relative to the source widget.

To receive mouse events from a button add the implementation as a mouse listener of a button.

MyMouseListener myMouseListener;
gcn::Button button;

void foo()
{
    button.addMouseListener(&MouseListener);
}
An example of adding a mouse listener to a button.

As with key events most implemented widgets in Guichan which uses mouse input are mouse listeners themselves and listen for mouse events on themselves.

#include <guichan.hpp>
#include <iostream>

class MyCustomWidget: public gcn::Widget, public gcn::MouseListener
{
public:
    MyCustomWidget()
    {
        addMouseListener(this);
    }     

    void mousePressed(gcn::MouseEvent& mouseEvent)
    {
        std::cout << "Mouse pressed: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl;
    }
   
    void mouseReleased(gcn::MouseEvent& mouseEvent)
    {  
        std::cout << "Mouse pressed: " << mouseEvent.getX() << " " << mouseEvent.getY() << std::endl;
    }

};
An example of a widget which is only capable of printing some mouse events.

Action events

Action events are events which concerns widgets. An action event is fired by a widget and distributed to all action listeners of the widget, thus the source of the event is the widget that fires the event. What makes the widget fire an action event depends on the widget. An example of an action event is a button which is pressed or a list box where an item in the list is selected.

Receiving action events

To receive action events one must implement an action listener. In the example below the action id of the event is printed. The action id is a string which can be set to all widgets by calling Widget::setActionId. A neat thing with the action id is that two widgets can have the same action id and that way two widgets actions can be treated equally with the same action listener.

#include <guichan.hpp>
#include <iostream>

class MyActionListener : public gcn::ActionListener
{
    void action(const gcn::ActionEvent& actionEvent)
    {
        std::cout << "Action : " << actionEvent.getId() << std::endl;
    }
};   
An example of an implementated action listener which prints the id of the action.

To receive action events from a button add the action listener implementation to the action listeners of the button.

MyActionListener myActionListener;
gcn::Button button;

void foo()
{
    button.addActionListener(&myActionListener);
}

An example of adding an action listener to a button.

Death events

Death events are events which concerns the death of a widget. When a widget dies, or it's destructor is called, it sends a death event to all it's death listener. The source widget is of course the widget. Death events, unlike other events, doesn't have it's own event class but utilises the Event class. This is because the only relavent information of a death of a widget is the source widget.

Receiving death events

To receive death events one must implement a death listener.

#include <guichan.hpp>
#include <iostream>

class MyDeathListener : public gcn::DeathListener
{
    void death(const gcn::Event& event)
    {
        std::cout << "Death : " << event.getSource() << std::endl;
    }
};   
An example of an implementated death listener which prints the pointer to the widget who died.

To receive death events from a button add the death listener implementation to the death listeners of the button.

MyDeathListener myDeathListener;
gcn::Button button;

void foo()
{
    button.addDeathListener(&myDeathListener);
}
An example of adding a death listener to a button.

Focus events

Focus events are events which concerns focus of a widget. When a widget gets focus or loses focus a focus event is sent to all focus listeners of the widget. The source widget is of course the widget the focus concerns. Focus events doesn't have it's own event class but utilises the Event class. This is because the only relavent information of a focus event is the source widget.

Receiving focus events

To receive focus events one must implement a focus listener.

#include <guichan.hpp>
#include <iostream>

class MyFocusListener : public gcn::FocusListener
{
    void focusGained(const gcn::Event& event)
    {
        std::cout << "Focus gained: " << event.getSource() << std::endl;
    }

    void focusLost(const gcn::Event& event)
    {
        std::cout << "Focus lost : " << event.getSource() << std::endl;
    }
};   
An example of an implementated focus listener which prints the pointer to the widget the focus changes concerns.

To receive focus events from a button add the focus listener implementation to the focus listeners of the button.

MyFocusListener myFocusListener;
gcn::Button button;

void foo()
{
    button.addFocusListener(&myFocusListener);
}
An example of adding a focus listener to a button.