mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Nanoleaf fixes and enhancements
This commit is contained in:
parent
8f9d94e390
commit
1e85dac292
@ -10,13 +10,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Added
|
||||
|
||||
- Nanoleaf: Wizard to generate user authorization token allowing users to configure the device via a single window
|
||||
- Nanoleaf: Generation of a default layout per device's configuration
|
||||
|
||||
### Changed
|
||||
|
||||
### Fixed
|
||||
- Fixed missing Include limits in QJsonSchemaChecker
|
||||
- Fixed dependencies for deb packages in Debian Bookworm
|
||||
- Nanoleaf: "Panel numbering sequence" was not configurable any longer
|
||||
- Nanoleaf: Number of panels increased during retries (#1643)
|
||||
|
||||
## Removed
|
||||
- Nanoleaf: Removed "Start Position" in favour of the general Blacklist feature provided
|
||||
|
||||
## [2.0.15](https://github.com/hyperion-project/hyperion.ng/releases/tag/2.0.15) - 2023-02
|
||||
|
||||
|
@ -46,6 +46,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer" style="text-align:right">
|
||||
<button id='btn_layout_controller' class="btn btn-primary" disabled data-toggle="tooltip" data-placement="top" title="Generate a layout for the configured device">
|
||||
<i class="fa fa-fw fa-save"></i><span data-i18n="wiz_layout">Generate Layout</span>
|
||||
</button>
|
||||
<button id='btn_test_controller' class="btn btn-primary" disabled data-toggle="tooltip" data-placement="top" title="Identify configured device by lighting it up">
|
||||
<i class="fa fa-fw fa-save"></i><span data-i18n="wiz_identify">Identify/Test</span>
|
||||
</button>
|
||||
|
@ -118,6 +118,8 @@
|
||||
"conf_leds_layout_cl_vleddepth": "Vertical LED depth",
|
||||
"conf_leds_layout_frame": "Classic Layout (LED Frame)",
|
||||
"conf_leds_layout_generatedconf": "Generated/Current LED Configuration",
|
||||
"conf_leds_layout_generation_success": "LED Layout generated sucessfully",
|
||||
"conf_leds_layout_generation_error": "LED Layout was not generated",
|
||||
"conf_leds_layout_intro": "You also need an LED layout, which reflects your LED positions. The classic layout is the usually used TV frame, but we also support LED matrix (LED walls) creation. The view on this layout is ALWAYS from the FRONT of your TV.",
|
||||
"conf_leds_layout_ma_cabling": "Cabling",
|
||||
"conf_leds_layout_ma_direction": "Direction",
|
||||
@ -1121,6 +1123,8 @@
|
||||
"wiz_identify": "Identify",
|
||||
"wiz_identify_tip": "Identify configured device by lighting it up",
|
||||
"wiz_identify_light": "Identify $1",
|
||||
"wiz_layout": "Generate Layout",
|
||||
"wiz_layout_tip": "Generate a layout for the configured device",
|
||||
"wiz_ids_disabled": "Deactivated",
|
||||
"wiz_ids_entire": "Whole picture",
|
||||
"wiz_nanoleaf_failure_auth_token": "Please press the Nanoleaf Power On/Off button within 30 seconds",
|
||||
|
@ -1050,7 +1050,7 @@ $(document).ready(function () {
|
||||
// change save button state based on validation result
|
||||
conf_editor.validate().length || window.readOnlyMode ? $('#btn_submit_controller').prop('disabled', true) : $('#btn_submit_controller').prop('disabled', false);
|
||||
|
||||
// led controller sepecific wizards
|
||||
// LED controller specific wizards
|
||||
$('#btn_wiz_holder').html("");
|
||||
$('#btn_led_device_wiz').off();
|
||||
|
||||
@ -1091,6 +1091,7 @@ $(document).ready(function () {
|
||||
var colorOrderDefault = "rgb";
|
||||
var filter = {};
|
||||
|
||||
$('#btn_layout_controller').hide();
|
||||
$('#btn_test_controller').hide();
|
||||
|
||||
switch (ledType) {
|
||||
@ -1684,6 +1685,33 @@ $(document).ready(function () {
|
||||
$("#leddevices").val(window.serverConfig.device.type);
|
||||
$("#leddevices").trigger("change");
|
||||
|
||||
// Generate layout for LED-Device
|
||||
$("#btn_layout_controller").off().on("click", function () {
|
||||
var ledType = $("#leddevices").val();
|
||||
var isGenerated = false;
|
||||
|
||||
switch (ledType) {
|
||||
case "nanoleaf":
|
||||
var host = conf_editor.getEditor("root.specificOptions.host").getValue();
|
||||
var ledDeviceProperties = devicesProperties[ledType][host];
|
||||
if (ledDeviceProperties) {
|
||||
var panelOrderTopDown = conf_editor.getEditor("root.specificOptions.panelOrderTopDown").getValue() === "top2down";
|
||||
var panelOrderLeftRight = conf_editor.getEditor("root.specificOptions.panelOrderLeftRight").getValue() === "left2right";
|
||||
var ledArray = nanoleafGeneratelayout(ledDeviceProperties.panelLayout.layout, panelOrderTopDown, panelOrderLeftRight);
|
||||
aceEdt.set(ledArray);
|
||||
isGenerated = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
if (isGenerated) {
|
||||
showInfoDialog('success', "", $.i18n('conf_leds_layout_generation_success'));
|
||||
} else {
|
||||
showInfoDialog('error', "", $.i18n('conf_leds_layout_generation_error'));
|
||||
}
|
||||
});
|
||||
|
||||
// Identify/ Test LED-Device
|
||||
$("#btn_test_controller").off().on("click", function () {
|
||||
var ledType = $("#leddevices").val();
|
||||
@ -2163,6 +2191,7 @@ async function identify_device(type, params) {
|
||||
}
|
||||
|
||||
function updateElements(ledType, key) {
|
||||
var canLayout = false;
|
||||
if (devicesProperties[ledType][key]) {
|
||||
var hardwareLedCount = 1;
|
||||
switch (ledType) {
|
||||
@ -2183,9 +2212,9 @@ function updateElements(ledType, key) {
|
||||
|
||||
if (ledProperties) {
|
||||
hardwareLedCount = ledProperties.ledCount;
|
||||
canLayout = true;
|
||||
}
|
||||
conf_editor.getEditor("root.generalOptions.hardwareLedCount").setValue(hardwareLedCount);
|
||||
|
||||
break;
|
||||
|
||||
case "udpraw":
|
||||
@ -2234,11 +2263,19 @@ function updateElements(ledType, key) {
|
||||
}
|
||||
|
||||
if (!conf_editor.validate().length) {
|
||||
if (canLayout) {
|
||||
$("#btn_layout_controller").show();
|
||||
$('#btn_layout_controller').prop('disabled', false);
|
||||
} else {
|
||||
$('#btn_layout_controller').hide();
|
||||
}
|
||||
|
||||
if (!window.readOnlyMode) {
|
||||
$('#btn_submit_controller').attr('disabled', false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$('#btn_layout_controller').prop('disabled', true);
|
||||
$('#btn_submit_controller').attr('disabled', true);
|
||||
}
|
||||
}
|
||||
@ -2416,4 +2453,112 @@ function updateElementsWled(ledType, key) {
|
||||
}
|
||||
showInputOptionForItem(conf_editor, "root.specificOptions.segments", "switchOffOtherSegments", showAdditionalOptions);
|
||||
}
|
||||
function sortByPanelCoordinates(arr, topToBottom, leftToRight) {
|
||||
arr.sort((a, b) => {
|
||||
//Nanoleaf corodinates start at bottom left, therefore reverse topToBottom
|
||||
if (!topToBottom) {
|
||||
if (a.y === b.y) {
|
||||
if (leftToRight) {
|
||||
return a.x - b.x;
|
||||
} else {
|
||||
return b.x - a.x;
|
||||
}
|
||||
} else {
|
||||
return a.y - b.y;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (a.y === b.y) {
|
||||
if (leftToRight) {
|
||||
return a.x - b.x;
|
||||
} else {
|
||||
return b.x - a.x;
|
||||
}
|
||||
} else {
|
||||
return b.y - a.y;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function nanoleafGeneratelayout(layout, panelOrderTopDown, panelOrderLeftRight) {
|
||||
|
||||
// Dictionary for Nanoleaf shape types
|
||||
let shapeTypes = {
|
||||
0: { name: "LightsTriangle", sideLengthX: 150, sideLengthY: 150 },
|
||||
1: { name: "LightsRythm", sideLengthX: 0, sideLengthY: 0 },
|
||||
2: { name: "Square", sideLengthX: 100, sideLengthY: 100 },
|
||||
3: { name: "SquareControllerMaster", sideLengthX: 100, sideLengthY: 100 },
|
||||
4: { name: "SquareControllerPassive", sideLengthX: 100, sideLengthY: 100 },
|
||||
5: { name: "PowerSupply", sideLengthX: 100, sideLengthY: 100 },
|
||||
7: { name: "ShapesHexagon", sideLengthX: 67, sideLengthY: 67 },
|
||||
8: { name: "ShapesTriangle", sideLengthX: 134, sideLengthY: 134 },
|
||||
9: { name: "ShapesMiniTriangle", sideLengthX: 67, sideLengthY: 67 },
|
||||
12: { name: "ShapesController", sideLengthX: 0, sideLengthY: 0 },
|
||||
14: { name: "ElementsHexagon", sideLengthX: 134, sideLengthY: 134 },
|
||||
15: { name: "ElementsHexagonCorner", sideLengthX: 33.5, sideLengthX: 58 },
|
||||
16: { name: "LinesConnector", sideLengthX: 11, sideLengthY: 11 },
|
||||
17: { name: "LightLines", sideLengthX: 154, sideLengthY: 154 },
|
||||
18: { name: "LightLinesSingleZone", sideLengthX: 77, sideLengthY: 77 },
|
||||
19: { name: "ControllerCap", sideLengthX: 11, sideLengthY: 11 },
|
||||
20: { name: "PowerConnector", sideLengthX: 11, sideLengthY: 11 },
|
||||
999: { name: "Unknown", sideLengthX: 100, sideLengthY: 100 }
|
||||
};
|
||||
|
||||
let { positionData, numPanels, sideLength } = layout;
|
||||
var minX = positionData[0].x;
|
||||
var maxX = positionData[0].x;
|
||||
var minY = positionData[0].y;
|
||||
var maxY = positionData[0].y;
|
||||
|
||||
//Define capture rectangle per panel
|
||||
var factorPartial = 0.25;
|
||||
positionData.forEach(panel => {
|
||||
|
||||
if (shapeTypes[panel.shapeType] == undefined) {
|
||||
panel.shapeType = 999;
|
||||
}
|
||||
|
||||
panel.maxX = panel.x + shapeTypes[panel.shapeType].sideLengthX * factorPartial;
|
||||
panel.maxY = panel.y + shapeTypes[panel.shapeType].sideLengthY * factorPartial;
|
||||
panel.shapeName = shapeTypes[panel.shapeType].name;
|
||||
|
||||
if (panel.maxX > maxX) {
|
||||
maxX = panel.maxX;
|
||||
}
|
||||
if (panel.x < minX) {
|
||||
minX = panel.x;
|
||||
}
|
||||
if (panel.maxY > maxY) {
|
||||
maxY = panel.maxY;
|
||||
}
|
||||
if (panel.y < minY) {
|
||||
minY = panel.y
|
||||
}
|
||||
});
|
||||
|
||||
const width = (maxX - minX);
|
||||
const height = (maxY - minY);
|
||||
const scaleX = 1 / width;
|
||||
const scaleY = 1 / height;
|
||||
|
||||
var layoutObjects = [];
|
||||
var i = 0;
|
||||
|
||||
sortByPanelCoordinates(positionData, panelOrderTopDown, panelOrderLeftRight);
|
||||
positionData.forEach(panel => {
|
||||
|
||||
let layoutObject = {
|
||||
name: i + "-" + panel.panelId,
|
||||
hmin: (panel.x - minX) * scaleX,
|
||||
hmax: (panel.maxX - minX) * scaleX,
|
||||
//Nanoleaf corodinates start at bottom left, therefore reverse vertical positioning
|
||||
vmin: 1 - ((panel.maxY - minY) * scaleY),
|
||||
vmax: 1 - ((panel.y - minY) * scaleY)
|
||||
};
|
||||
++i;
|
||||
|
||||
layoutObjects.push(JSON.parse(JSON.stringify(layoutObject)));
|
||||
});
|
||||
return layoutObjects;
|
||||
}
|
||||
|
@ -2240,7 +2240,7 @@ function createNanoleafUserAuthorization() {
|
||||
abortConnection(UserInterval);
|
||||
clearInterval(UserInterval);
|
||||
|
||||
showNotification('warning', $.i18n('wiz_nanoleaf_failure_auth_token'), $.i18n('wiz_nanoleaf_failure_auth_token_t'))
|
||||
showNotification('warning', $.i18n('wiz_nanoleaf_failure_auth_token'), $.i18n('wiz_nanoleaf_failure_auth_token_t'));
|
||||
|
||||
resetWizard(true);
|
||||
}
|
||||
|
@ -820,6 +820,69 @@ bool SettingsManager::handleConfigUpgrade(QJsonObject& config)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (type == "nanoleaf")
|
||||
{
|
||||
if (newDeviceConfig.contains("panelStartPos"))
|
||||
{
|
||||
newDeviceConfig.remove("panelStartPos");
|
||||
migrated = true;
|
||||
}
|
||||
|
||||
if (newDeviceConfig.contains("panelOrderTopDown"))
|
||||
{
|
||||
QString panelOrderTopDown;
|
||||
if (newDeviceConfig["panelOrderTopDown"].isDouble())
|
||||
{
|
||||
panelOrderTopDown = QString(newDeviceConfig["panelOrderTopDown"].toInt());
|
||||
}
|
||||
else
|
||||
{
|
||||
panelOrderTopDown = newDeviceConfig["panelOrderTopDown"].toString();
|
||||
}
|
||||
|
||||
if (newDeviceConfig["panelOrderTopDown"] == "0")
|
||||
{
|
||||
newDeviceConfig["panelOrderTopDown"] = "top2down";
|
||||
migrated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newDeviceConfig["panelOrderTopDown"] == "1")
|
||||
{
|
||||
newDeviceConfig["panelOrderTopDown"] = "bottom2up";
|
||||
migrated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newDeviceConfig.contains("panelOrderLeftRight"))
|
||||
{
|
||||
QString panelOrderLeftRight;
|
||||
if (newDeviceConfig["panelOrderLeftRight"].isDouble())
|
||||
{
|
||||
panelOrderLeftRight = QString(newDeviceConfig["panelOrderLeftRight"].toInt());
|
||||
}
|
||||
else
|
||||
{
|
||||
panelOrderLeftRight = newDeviceConfig["panelOrderLeftRight"].toString();
|
||||
}
|
||||
|
||||
if (newDeviceConfig["panelOrderLeftRight"] == "0")
|
||||
{
|
||||
newDeviceConfig["panelOrderLeftRight"] = "left2right";
|
||||
migrated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newDeviceConfig["panelOrderLeftRight"] == "1")
|
||||
{
|
||||
newDeviceConfig["panelOrderTopDown"] = "right2left";
|
||||
migrated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (migrated)
|
||||
|
@ -33,7 +33,6 @@ const char CONFIG_BRIGHTNESS_OVERWRITE[] = "overwriteBrightness";
|
||||
|
||||
const char CONFIG_PANEL_ORDER_TOP_DOWN[] = "panelOrderTopDown";
|
||||
const char CONFIG_PANEL_ORDER_LEFT_RIGHT[] = "panelOrderLeftRight";
|
||||
const char CONFIG_PANEL_START_POS[] = "panelStartPos";
|
||||
|
||||
const bool DEFAULT_IS_RESTORE_STATE = true;
|
||||
const bool DEFAULT_IS_BRIGHTNESS_OVERWRITE = true;
|
||||
@ -123,8 +122,6 @@ LedDeviceNanoleaf::LedDeviceNanoleaf(const QJsonObject& deviceConfig)
|
||||
, _apiPort(API_DEFAULT_PORT)
|
||||
, _topDown(true)
|
||||
, _leftRight(true)
|
||||
, _startPos(0)
|
||||
, _endPos(0)
|
||||
, _extControlVersion(EXTCTRLVER_V2)
|
||||
, _panelLedCount(0)
|
||||
{
|
||||
@ -178,24 +175,8 @@ bool LedDeviceNanoleaf::init(const QJsonObject& deviceConfig)
|
||||
Debug(_log, "Set Brightness to : %d", _brightness);
|
||||
|
||||
// Read panel organisation configuration
|
||||
if (deviceConfig[CONFIG_PANEL_ORDER_TOP_DOWN].isString())
|
||||
{
|
||||
_topDown = deviceConfig[CONFIG_PANEL_ORDER_TOP_DOWN].toString().toInt() == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_topDown = deviceConfig[CONFIG_PANEL_ORDER_TOP_DOWN].toInt() == 0;
|
||||
}
|
||||
|
||||
if (deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].isString())
|
||||
{
|
||||
_leftRight = deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].toString().toInt() == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_leftRight = deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].toInt() == 0;
|
||||
}
|
||||
_startPos = deviceConfig[CONFIG_PANEL_START_POS].toInt(0);
|
||||
_topDown = deviceConfig[CONFIG_PANEL_ORDER_TOP_DOWN].toString("top2down") == "top2down";
|
||||
_leftRight = deviceConfig[CONFIG_PANEL_ORDER_LEFT_RIGHT].toString("left2right") == "left2right";
|
||||
|
||||
isInitOK = true;
|
||||
}
|
||||
@ -262,6 +243,7 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
|
||||
QJsonObject jsonLayout = jsonPanelLayout[PANEL_LAYOUT].toObject();
|
||||
|
||||
_panelLedCount = getHwLedCount(jsonLayout);
|
||||
_devConfig["hardwareLedCount"] = _panelLedCount;
|
||||
|
||||
int panelNum = jsonLayout[PANEL_NUM].toInt();
|
||||
const QJsonArray positionData = jsonLayout[PANEL_POSITIONDATA].toArray();
|
||||
@ -331,20 +313,13 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
|
||||
}
|
||||
}
|
||||
|
||||
_devConfig["hardwareLedCount"] = _panelLedCount;
|
||||
|
||||
Debug(_log, "PanelsNum : %d", panelNum);
|
||||
Debug(_log, "PanelLedCount : %d", _panelLedCount);
|
||||
Debug(_log, "Sort Top>Down : %d", _topDown);
|
||||
Debug(_log, "Sort Left>Right: %d", _leftRight);
|
||||
|
||||
// Check. if enough panels were found.
|
||||
int configuredLedCount = this->getLedCount();
|
||||
_endPos = _startPos + configuredLedCount - 1;
|
||||
|
||||
Debug(_log, "Sort Top>Down : %d", _topDown);
|
||||
Debug(_log, "Sort Left>Right: %d", _leftRight);
|
||||
Debug(_log, "Start Panel Pos: %d", _startPos);
|
||||
Debug(_log, "End Panel Pos : %d", _endPos);
|
||||
|
||||
if (_panelLedCount < configuredLedCount)
|
||||
{
|
||||
QString errorReason = QString("Not enough panels [%1] for configured LEDs [%2] found!")
|
||||
@ -359,16 +334,6 @@ bool LedDeviceNanoleaf::initLedsConfiguration()
|
||||
{
|
||||
Info(_log, "%s: More panels [%d] than configured LEDs [%d].", QSTRING_CSTR(this->getActiveDeviceType()), _panelLedCount, configuredLedCount);
|
||||
}
|
||||
|
||||
// Check, if start position + number of configured LEDs is greater than number of panels available
|
||||
if (_endPos >= _panelLedCount)
|
||||
{
|
||||
QString errorReason = QString("Start panel [%1] out of range. Start panel position can be max [%2] given [%3] panel available!")
|
||||
.arg(_startPos).arg(_panelLedCount - configuredLedCount).arg(_panelLedCount);
|
||||
|
||||
this->setInError(errorReason, false);
|
||||
isInitOK = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isInitOK;
|
||||
@ -584,7 +549,8 @@ bool LedDeviceNanoleaf::powerOn()
|
||||
QString errorReason = QString("Power-on request failed with error: '%1'").arg(response.getErrorReason());
|
||||
this->setInError(errorReason);
|
||||
on = false;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
on = true;
|
||||
}
|
||||
|
||||
@ -742,7 +708,8 @@ bool LedDeviceNanoleaf::restoreState()
|
||||
{
|
||||
Warning(_log, "%s restoring effect failed with error: '%s'", QSTRING_CSTR(_activeDeviceType), QSTRING_CSTR(response.getErrorReason()));
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Warning(_log, "%s restoring effect failed with error: Cannot restore dynamic or solid effect. Device is switched off", QSTRING_CSTR(_activeDeviceType));
|
||||
_originalIsOn = false;
|
||||
}
|
||||
@ -833,25 +800,14 @@ int LedDeviceNanoleaf::write(const std::vector<ColorRgb>& ledValues)
|
||||
int ledCounter = 0;
|
||||
for (int panelCounter = 0; panelCounter < _panelLedCount; panelCounter++)
|
||||
{
|
||||
int panelID = _panelIds[panelCounter];
|
||||
|
||||
// Set panels configured
|
||||
if (panelCounter >= _startPos && panelCounter <= _endPos) {
|
||||
color = static_cast<ColorRgb>(ledValues.at(ledCounter));
|
||||
++ledCounter;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set panels not configured to black
|
||||
color = ColorRgb::BLACK;
|
||||
DebugIf(verbose3, _log, "[%d] >= panelLedCount [%d] => Set to BLACK", panelCounter, _panelLedCount);
|
||||
}
|
||||
|
||||
// Set panelID
|
||||
int panelID = _panelIds[panelCounter];
|
||||
qToBigEndian<quint16>(static_cast<quint16>(panelID), udpbuffer.data() + i);
|
||||
i += 2;
|
||||
|
||||
// Set panel's color LEDs
|
||||
color = static_cast<ColorRgb>(ledValues.at(ledCounter));
|
||||
++ledCounter;
|
||||
udpbuffer[i++] = static_cast<char>(color.red);
|
||||
udpbuffer[i++] = static_cast<char>(color.green);
|
||||
udpbuffer[i++] = static_cast<char>(color.blue);
|
||||
|
@ -210,8 +210,6 @@ private:
|
||||
|
||||
bool _topDown;
|
||||
bool _leftRight;
|
||||
int _startPos;
|
||||
int _endPos;
|
||||
|
||||
//Nanoleaf device details
|
||||
QString _deviceModel;
|
||||
|
@ -72,41 +72,28 @@
|
||||
"propertyOrder": 7
|
||||
},
|
||||
"panelOrderTopDown": {
|
||||
"type": "integer",
|
||||
"type": "string",
|
||||
"title": "edt_dev_spec_order_top_down_title",
|
||||
"enum": [ 0, 1 ],
|
||||
"default": 0,
|
||||
"enum": [ "top2down", "bottom2up" ],
|
||||
"default": "top2down",
|
||||
"required": true,
|
||||
"options": {
|
||||
"enum_titles": [ "edt_conf_enum_top_down", "edt_conf_enum_bottom_up" ]
|
||||
},
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"access": "advanced",
|
||||
"propertyOrder": 8
|
||||
},
|
||||
"panelOrderLeftRight": {
|
||||
"type": "integer",
|
||||
"type": "string",
|
||||
"title": "edt_dev_spec_order_left_right_title",
|
||||
"enum": [ 0, 1 ],
|
||||
"default": 0,
|
||||
"enum": [ "left2right", "right2left" ],
|
||||
"default": "left2right",
|
||||
"required": true,
|
||||
"options": {
|
||||
"enum_titles": [ "edt_conf_enum_left_right", "edt_conf_enum_right_left" ]
|
||||
},
|
||||
"minimum": 0,
|
||||
"maximum": 1,
|
||||
"access": "advanced",
|
||||
"propertyOrder": 9
|
||||
},
|
||||
"panelStartPos": {
|
||||
"type": "integer",
|
||||
"title": "edt_dev_spec_panel_start_position",
|
||||
"step": 1,
|
||||
"minimum": 0,
|
||||
"default": 0,
|
||||
"access": "advanced",
|
||||
"propertyOrder": 10
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
|
Loading…
Reference in New Issue
Block a user