Qt Bindings

Tangible engine enables users to take advantage of specially engineered physical objects that can be recognized by Ideum touch-enabled products. The objects, called tangibles, are made of conductive material that mimics touches on the surface of a p-cap display. On the software end, the Tangible Engine is a windows service that runs in the background, awaiting the connection of client apps that require tangible recognition capabilities. A service model was chosen to enable Ideum to create and deploy fixes and new features without requiring clients to rebuild their own apps. The Qt bindings use a TCP socket to communicate with a locally running service.

Setting up the Engine

The TangibleClient class is designed to be set as a context property, so that it can be accessed directly in QML. To do this, create an instance of a TangibleClient in main.cpp, set it as a context property in the engine, and call its setup call. The TangibleClient will setup a TCP connection, connect to the service, request a patterns list, sends updates each frame, and updates the QAbstractList of tangibles. TangibleClient may be constructed with an optional boolean as a third argument to enable or disable logging; this boolean defaults to true.

Note: The port value (ie. 4949) passed to the TangibleClient constructor must match the port being used by the Tangible Engine Service, or a connection cannot be made.

The TangibleSimulator is an optional class that can be used as a drop-in replacement for TangibleClient. It contains the same interface, and should also be registered in the root context as TangibleEngine. It will not provide functionality on its own - rather, if the Qml project also includes the TangibleSimulator component, this component will become active and enable users to place simulated tangibles in the scene. In the main.cpp below, a preprocessor directive of #define USE_TANGIBLE_SIMULATOR is used as a toggle for this functionality.

#include <TangibleEngine/tangibleclient.h>
#include <TangibleEngine/tangiblesimulator.h>

#define USE_TANGIBLE_SIMULATOR

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);
  app.processEvents();
  app.setQuitOnLastWindowClosed(true);

#ifdef USE_TANGIBLE_SIMULATOR
  ///Instantiate a Tangible Client with the simulator class.
    TangibleSimulator * client = new TangibleSimulator();
#else
  ///Instantiate a Tangible Client with the desired port.
    TangibleClient * client = new TangibleClient("Localhost", 4949);
#endif

  QQmlApplicationEngine engine;

  ///Register type Tangible with Engine
  qmlRegisterType<Tangible>("Tangibles",2,0,"Tangible");

  ///Set the client instance as a context property
  engine.rootContext()->setContextProperty("TangibleEngine", client);

  engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

  QWindow *main_window = qobject_cast<QWindow*>(engine.rootObjects().first());

  ///Call the client setup method, passing the main_window of the application
  client->setup(main_window);

  return app.exec();
}

Interfacing with the Engine

Interfacing with the Engine through qml is very simple. With the instance of TangibleClient set as a context property in the qml engine, all you need to do is reference the QAbstractList titled tangibles. In this example, we use the tangibles list as the model for a Repeater of TangibleVisual.qml components.

import QtQuick 2.9
import QtQuick.Window 2.2

import "TangibleEngine"

Window {

    id: mainWindow

    visibility: "Windowed"
    visible: true

    Item
    {
        focus: true
        Keys.onEscapePressed: Qt.quit()
    }

    ///This repeater is populated with the Tangible Engine QAbstractListModel and will update
    /// as tangibles are placed, moved, and removed.
    Repeater
    {
        model: TangibleEngine.tangibles

        TangibleVisual {  tangible: model.tangible }
    }

    ///This component will only be visible if TangibleEngine.isSimulator is true.
    TangibleSimulator {}
}

The TangibleVisual.qml component handles the visual representation of the recognized tangible, including its placement location, rotation, and other related information.

The TangibleSimulator.qml component resides in the TangibleEngine directory (note the import "TangibleEngine" directive). If included, it should reside at the top level above other components within the window context - it will auto-fill to the window's area and rescale itself based on a design resolution of 1920x1080. It will only be active if TangibleEngine.isSimulator is true; this is the case for the TangibleSimulator C++ class referenced above.

Last Updated: 9/8/2020, 9:37:23 AM