Integrating custom controls in Orbiter
This page was written by Pluto and imported with their permission when LinuxMCE branched off in February, 2007. In general any information should apply to LinuxMCE. However, this page should be edited to reflect changes to LinuxMCE and remove old references to Pluto. |
A DesignObj is a graphic object from Orbiter. Each DesignObj may be a collection of DesignObj children and so on. On parent DesignObj can be associated with a screen, which gives the programmer the possibility to do custom additional actions with that DesignObj.
Contents
How to associate a DesignObj to a screen
Once the parent design object is created with the Designer, go in pluto_main database and insert into Screen table a record with a description and few comments about the new screen. Then check Screen_DesignObj table and add a recording to link the screen with the designobj. You might also want to specify the UI and the Skin.
How to use ScreenGen to regenerate screens and how to use it
Run ScreenGen with -h <host> command line parameter and you should see in src/Gen_Devices/AllScreens.h that handlers for your need screens were added.
Let's say your screen has PK_Screen = 39, with the description "Computing":
In Screen_DesignObj, you should have something like this:
Understand AllScreens.h and ScreenHandlerBase class.
There is another table in the database, Screen_CommandParameter which allows you to associate a screen with a collection of command parameters. This means you can send a "go to screen" command and attach to it this collection of parameters.
AllScreens.h header file contains inline definitions for wrapper command classes (SCREEN_* classese) which allow you to send a "go to screen" command with additional parameters, without creating the message "by hand". And example:
From other application, the class can be used like this:
SCREEN_SingleCameraViewOnly screenSingleCameraViewOnly(DeviceIDFrom, DeviceIDTo, iPK_Device);
SendCommand(screenSingleCameraViewOnly);
ScreenHandler class is derived from ScreenHandlerBase class. The ScreenHandlerBase has a basing implementation for each screen, like this:
virtual void SCREEN_QuadViewCameras(long PK_Screen, string sList_PK_Device){ GotoScreen(PK_Screen); }
ScreenHandlerBase already demultiplexes each "go to screen" command and calls the right SCREEN_* method and also deserializes the command parameters. In order to add extrafunctionality for that screen, you will need to derive that virtual method with ScreenHandler class (for screens available for all orbiter) or OSDScreenHandler class (which has the handlers only for linux OSD Orbiter).
ScreenHandler and how to register a callback
Once you have derivated a SCREEN method in a ScreenHandlerBase's derived class, you may register few callbacks. So far, this is the list with callback types you can register:
enum CallBackType {
cbUnused, cbDataGridSelected, cbObjectSelected, cbOnDialogCreate, // create a unique dialog cbOnDialogDelete, // close dialog without saving data cbOnDialogRefresh, // refresh dialog with new data cbOnDialogSave, // save data from dialog cbOnDialogWaitUser, // wait for an user action cbOnKeyDown, cbOnKeyUp, cbOnMouseDown, cbOnMouseUp, cbCapturedKeyboardBufferChanged, cbOnTimer, cbMessageIntercepted, cbOnRenderScreen, cbOnGotoScreen
};
For each type of callback, your registered callback can be notified when an event is fired with extra data. That extra data is actually a derived class from CallBackData class.
Let's say we want to register a callback for "orbiter selected" event in SCREEN_CountryWizard method. We'll do something like this:
where :
First time an event is fired, the registered callbacks of that type are executed first and then Orbiter's code for that event. Returning true in your callback will cancel Orbiter's code executing. Returning false will make Orbiter continue to process the event executing its internal code.
How to send task to task manager.
Task manager is a proxy between Orbiter and wx widgets. Since Orbiter is running in a different thread then wx widgets's dialogs, we needed a asynchronous method of communicating with WX. TaskManager is a thread-safe singleton, which means that only one instance of TaskManager will be available, it can be access from anywhere and it can manager multithreaded requests safetly.
Orbiter sends "tasks" to WX via TaskManager. A task has associated info about the dialog type, callback type, callback data and a task id (which is generated and managed by TaskManager). To do this, there are two methods in TaskManager :
void AddTask(Task *Event); void AddTaskAndWait(Task *Event);
AddTask allows you to send info to WX asynchronously. AddTaskAndWait allows you to send info to WX synchronously. Once the task is added in the queue, a conditional wait is made in the queue and when a task is processed, it wakes up and verifies if the task with the id added was processed or not. If yes, the method returns.
To create a task, you'll have to use TaskManager's CreateTask method.
Let's take an example:
To create a "speed control" wxdialog, we'll do a :
SpeedControlCallBackData *pSpeedControlData = new SpeedControlCallBackData(plutoRect);
Task *pTask = TaskManager::Instance().CreateTask(cbOnDialogCreate, E_Dialog_SpeedControl, pSpeedControlData);
TaskManager::Instance().AddTaskAndWait(pTask);
To delete the dialog, we'll use cbOnDialogDelete callback type and to refresh, cbOnDialogRefresh.
If we want to now there to create and delete the dialog, we may want to create a screen for the parent object of wx control and register callbacks in overriden SCREEN_* method from the screen handler class like this:
RegisterCallBack( cbOnDialogCreate, (ScreenHandlerCallBack)&OSDScreenHandler::SpeedControlCreate, new PositionCallBackData() );
RegisterCallBack( cbOnDialogDelete, (ScreenHandlerCallBack)&OSDScreenHandler::SpeedControlDelete, new PositionCallBackData() );
The new UI will allows you to manage wx widget's dialog as popups, via PopupManager class. ***comming soon***