🚧 Under Construction: This guide is still far from complete. We will improve it in the future.
The modularity of CosmoScout allows for easy feature extension through the use of plugins.
This documentation aims at understanding the basic plugin architecture and the available apis.
There are two types of plugins. There are normal plugins, which can be configured and add some features for the user to look at or interact with and there are plugin libraries, which provide some common classes for multiple plugins.
To create a new plugin you can either create all the files by hand, copying from another plugin or we provide PowerShell
scripts tools/New-Plugin.ps1
and tools/New-PluginLibrary.ps1
which will create all the relevant folders and files for you.
For documentation look inside the script.
If you are on Linux and want to use the script you can find a guide to install PowerShell on Linux here.
Plugin libraries are rather simple. They are basically a normal C++-Library, which depends on CosmoScout's core libraries.
They are prefixed with csl
, which stand for "CosmoScout Library".
The other plugin type is described in the sections below. It is prefixed with csp
, which stands for "CosmoScout Plugin".
...
Elements can be made addable to the gui by placing them in a gui
folder in the plugins source.
The install
step will copy those file.
csp-example-plugin
├ gui
│ ├ js
│ │ └ plugin.js
│ ├ css
│ │ └ plugin.css
│ └ plugin.html
└ src
└ ...
Content can be added to the sidebar in two places.
Plugins that need extensive configuration or are feature rich should add a designated plugin tab.
/// Adds a new tab to the side bar.
///
/// @param name The nam/title of the tab.
/// @param icon The name of the Material icon.
/// @param htmlFile The HTML file that describes the tabs contents.
GuiManager::addPluginTabToSideBarFromHTML(std::string const& name, std::string const& icon, std::string const& htmlFile);
Tab skeleton
<div class="strike">
<span>Plugin Section Headline</span>
</div>
<div class="row">
<div class="col-5">
Label name
</div>
<div class="col-1">
<i class="material-icons">Material Icon Name</i>
</div>
<div class="col-6">
<!-- <select> / <input> -->
</div>
</div>
<!-- ... rows -->
<div class="strike">
<span>Plugin Section Headline</span>
</div>
<div class="row">
<div class="col-6">
50% width label
</div>
<div class="col-6">
<!-- <select> / <input> / ... -->
</div>
</div>
<!-- ... rows -->
The settings section is the last tab in the sidebar and contains, as the name denotes, settings.
Settings should only include checkboxes for enabling or disabling features or radio groups to change modes.
/// Adds a new section to the settings tab.
///
/// @param name The name/title of the section.
/// @param htmlFile The HTML file that describes the sections contents.
GuiManager::addSettingsSectionToSideBarFromHTML(std::string const& name, std::string const& icon, std::string const& htmlFile);
Settings skeleton:
<div class="row">
<div class="col-7 offset-5">
<label class="checklabel">
<input type="checkbox" id="set_enable_example_feature" />
<i class="material-icons"></i>
<span>Example checkbox</span>
</label>
</div>
</div>
<div class="row">
<div class="col-5">
Example radio
</div>
<div class="col-7">
<label class="radiolabel">
<input name="example_radio" type="radio" id="set_example_mode_0" />
<span>Example mode 1</span>
</label>
</div>
<div class="col-7 offset-5">
<label class="radiolabel">
<input name="example_radio" type="radio" id="set_example_mode_1" />
<span>Example mode 2</span>
</label>
</div>
</div>
<!-- ... rows -->
/// Adds a link element to the head with a local file href.
///
/// @param fileName The filename in the css folder
GuiManager::addCSS(std::string const& fileName);
/// This can be used to initialize the DOM elements added to the sidebar with the methods above.
///
/// @param jsFile The javascript file that contains the source code.
GuiManager::executeJavascriptFile(std::string const& jsFile);
The global CosmoScout
object exposes several gui related helper methods.
One or more IApi
classes to be initialized and registered on the CosmoScout object.
This method allows you to register and initialize your plugins JavaScript.
In order to be registerable your api needs to extend the IApi
interface.
Registration means that your api is callable as CosmoScout.apiName.method(args)
.
// One api
CosmoScout.init(ExampleApi);
// Multiple apis
CosmoScout.init(FooApi, BarApi, BazApi);
Initializes the selectpicker
extension on all .simple-value-dropdown
elements.
A change event listener will be added which calls the CosmoScout application with the elements id and currently selected value.
This method is idempotent. Event listeners will be only added once.
CosmoScout.initDropDowns();
Adds a change event listener to all .checklabel input
elements. On change the CosmoScout application will be called with the elements id and current check state.
This method is idempotent. Event listeners will be only added once.
CosmoScout.initChecklabelInputs();
Adds a change event listener to all .radiolabel input
elements. On change the CosmoScout application will be called with the elements id.
This method is idempotent. Event listeners will be only added once.
CosmoScout.initRadiolabelInputs();
Adds an onclick listener to every element containing [data-call="'methodname'"]
.
The method name gets passed to CosmoScout.callNative.
Arguments can be passed by separating the content with ','
E.g.: 'fly_to','Africa' -> CosmoScout.callNative('fly_to', 'Africa')
method,arg1,...,argN -> CosmoScout.callNative('method', arg1, ..., argN)
Attribute content will be passed to eval. Strings need to be wrapped in '
This method is idempotent. Event listeners will be only added once.
<button data-call="'fly_to', 'Africa'">Fly to Africa</button>
CosmoScout.initDataCalls();
Initializes all [data-toggle="tooltip"]
and [data-toggle="tooltip-bottom"]
tooltips.
CosmoScout.initTooltips();
This method calls all init...
methods on the CosmoScout object.
Appends a <link rel="stylesheet">
to the head with url
as its href content.
CosmoScout.addCSS('https://example.com/example.css');
Removes a registered stylesheet by its url.
Your plugin should call this method upon de-initialization if it added any stylesheets.
CosmoScout.removeCSS('https://example.com/example.css');
Registers a template for later instantiation by CosmoScout.loadTemplateContent
.
This method gets called by GuiManager::addTemplate
.
const html = '<span>Example Html</span>';
// Append <span> to the body
CosmoScout.addTemplate('example', html);
Remove a registered template. Your plugin should call this method upon de-initialization if it added any template.
// Removes element from body
CosmoScout.removeTemplate('example');
In order to avoid mixing Html and JavaScript CosmoScout makes use of <template>
elements.
Template elements can contain arbitrary html that won't be displayed and parsed by the browser.
This allows to add complex html constructs to the GUI without cluttering your JavaScript.
CosmoScout.addTemplate
can be used to add <templates>
to the gui.
The return value is either false
if the template could not be loaded or a HTMLElement
.
Only the first html node of the template will be returned:
<!-- Only the <span> element will be returned -->
<template id="example-template">
<span>Example</span>
<p>Example2</p>
</template>
// Returns the <span> HTMLElement
CosmoScout.loadTemplateContent('example-template');
Clears the content of an element if it exists.
element
can either be a html id or a HTMLElement.
CosmoScout.clearHtml('container'); // Will clear #container
Initializes a noUiSlider.
id
the sliders html idmin
min slider valuemax
max slider valuestep
step sizestart
slider handle count and position
CosmoScout.initSlider('set_texture_gamma', 0.1, 3.0, 0.01, [1.0]);
Sets the value of a noUiSlider.
// Set value of #set_texture_gamma to 1
CosmoScout.setSliderValue('set_texture_gamma', 1);
// Set first handle value to 1, and second handle to 2
CosmoScout.setSliderValue('multi_handle_slider', 1, 2);
Clears the content of a dropdown.
// Clear options of <select id="example-dropdown">
CosmoScout.clearDropdown('example-dropdown');
Adds an option element to a dropdown.
id
dropdown idvalue
option valuetext
option textselected
default false, set to true to add the selected attribute
CosmoScout.addDropdownValue('example-dropdpwn', 'value', 'Example option');
CosmoScout.addDropdownValue('example-dropdpwn', 1, 'Example selected', true);
Sets the current value of a selectpicker.
Sets a radio button to checked.
Sets a checkboxs checked state to true/false.
Sets the value of a text input.
Only selects .text-input
s which descend .item-ID
.
Calls a method on the CosmoScout application.
fn
is the applications method name.
...args
is a list of arguments.
CosmoScout.callNative('fly_to', 'Africa');
CosmoScout.callNative('method', 'arg1', 'arg2', 'argN');
Called by init
. Registers an instantiated IApi
object on the CosmoScout object.
Makes the registered object accessible as CosmoScout.name
.
const api = new ExampleApi();
CosmoScout.register('exampleApi', api);
Removes a registered api object.
CosmoScout.remove('exampleApi');
Returns a registered api.
The IApi
interface contains a required name
member which is used by CosmoScout to identify the api.
The init
method should contain all code that is needed upon initializing the plugin. This method gets automatically called by the CosmoScout JavaScript api upon initialization.
class IApi {
// Name of api in camel case
// Required
name = "apiName";
// This gets called upon registration by CosmoScout
// Optional
init() {};
}
A typical plugin api could look something like this:
class ExamplePlugin extends IApi {
name = 'examplePlugin';
init() {
CosmoScout.initSlider('example_slider', 0, 100, 1, 0);
};
// This would be callable by the application as:
// mCosmoScoutGui->callJavascript("CosmoScout.examplePlugin.exampleMethod", arg);
// And on the JS side as CosmoScout.examplePlugin.exampleMethod(arg);
// Or internally as this.exampleMethod(arg)
exampleMethod(arg) {
//
}
}
// This ensures plugin initialization on file load
(() => {
CosmoScout.init(ExamplePlugin);
})();