What is a controller?

Using a controller, you can interact with the Map independently of the UI toolkit. Examples of these interactions are:

  • Map navigation

  • Selection

  • Editing the geometry of a feature

The main controller classes

IController

Interface to implement. An IController implementation interprets received events and triggers an action on the map. It receives toolkit-independent events — IInputEvent — and has a LayerList for controller-specific visualization.

IInputEvent

Toolkit-independent events that represent interactions of the user with the view. These events can represent both low-level input events — mouse move, press, or release for example — and more high-level gestures, such as click and drag. The API offers common event types:

  • Mouse pressed and released

  • Mouse clicks: sequence of a mouse press and a mouse release.

  • Mouse moves

  • Mouse drags: sequence of a mouse press, one or more mouse moves and a final mouse released.

  • Mouse scrolls

  • Key pressed and released

If you want to use input in an IController that isn’t available out-of-the-box, you can create a custom IInputEvent implementation.

Event Handlers

Reusable building blocks that use IInputEvent input to perform an action. The API offers basic handlers that you can use for the implementation of a controller. For example:

Map

The LuciadCPillar map can have at most one controller active at any time. You activate the controller using the setController method. When you activate a controller, any controller that was already active gets de-activated first.

How to implement or customize an IController

When you implement an IController, you receive events as parameters of the onEvent method. You can then choose an action to carry out, based on the event type and properties. A convenient way to do that is to pass on the event to an existing event handler or a new one.

These code snippets show you how you can do that:

Program (C++): Handling drag events
auto dragEvent = std::dynamic_pointer_cast<DragEvent>(inputEvent);
if (dragEvent) {
  auto mouseDragEvent = std::dynamic_pointer_cast<MouseDragEvent>(inputEvent);
  if (mouseDragEvent) {
    if (mouseDragEvent->getModifierKeys() == ModifierKeys::None) {
      if (mouseDragEvent->getMouseButton() == MouseButton::Left) {
        _panEventHandler->onDragEvent(dragEvent, _map);
      } else if (mouseDragEvent->getMouseButton() == MouseButton::Right) {
        _rotateEventHandler->onDragEvent(dragEvent, _map);
      }
    }
  }
}
Program (C#): Handling drag events
if (inputEvent is MouseDragEvent dragEvent)
{
    if (dragEvent.ModifierKeys == ModifierKeys.None)
    {
        if (dragEvent.MouseButton == MouseButton.Left)
        {
            _panEventHandler.OnDragEvent(dragEvent, _map);
        }
        else if (dragEvent.MouseButton == MouseButton.Right)
        {
            _rotateEventHandler.OnDragEvent(dragEvent, _map);
        }
    }
}
Program (C++): Handling scroll events
auto scrollEvent = std::dynamic_pointer_cast<ScrollEvent>(inputEvent);
if (scrollEvent && (scrollEvent->getModifierKeys() == ModifierKeys::None || scrollEvent->getModifierKeys() == ModifierKeys::Ctrl)) {
  double zoomFactor = scrollEvent->getModifierKeys() == ModifierKeys::Ctrl ? 2.0 : 0.5;
  ZoomEventHandler().onScrollEvent(scrollEvent, _map, zoomFactor);
}
Program (C#): Handling scroll events
if (inputEvent is ScrollEvent scrollEvent && (scrollEvent.ModifierKeys == ModifierKeys.None || scrollEvent.ModifierKeys == ModifierKeys.Ctrl))
{
    var zoomSpeed = scrollEvent.ModifierKeys == ModifierKeys.Ctrl ? 2.0 : 1.25;
    new ZoomEventHandler().OnScrollEvent(scrollEvent, _map, zoomSpeed);
}

How to add visualization to an IController

To respond to some user interactions, you may need to add visual components to the map. For instance, if a user interacts with a map feature to edit it, you need to display editing handles on the feature. Users can then change the feature by manipulating those handles.

If you need to add visual components to the map to respond to user interactions, your controller can implement the getLayerList method. You use it to return a LayerList to visualize controller-specific information such as handles.

If the controller’s layer list is a dedicated one, the map retrieves it when the controller is attached, and appends this list to its own layer list with the controller list on top.

You can also let the controller add a layer to the Map’s LayerList.

Both options have their advantages:

How to integrate IController in a UI toolkit

If you want to use your own UI Toolkit, you must map the toolkit events to IInputEvent instances. Once you have those IInputEvent instances, you can send them to the active IController using the onEvent method.

The API offers a utility class to make this easier: GestureRecognizer. This class transforms low-level UI events, such as move, press, or release, into more high-level IInputEvent objects, such as drag and click.

The sample integration code also has utility classes that forward Qt or WPF events to a GestureRecognizer and map the resulting IInputEvent to the active controller:

  • Qt (QML) : QQuickMapObject

  • Qt (QWidget) : QMapWidget

  • WPF : WpfMapControl