mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
UI and Web updates (#1421)
* Stop Web-Capture when priority changes * Remote control UI: Treat duration=0 as endless * Stop Web-Capture on non-Image events changes * LED Matrix Layout - Support vertical cabling direction * Additional Yeelight models * Treat http headers case insensitive * Update change log * Treat http headers case insensitive (consider Qt version) * API - Consider provided format when setImage * UI - Support Boblight configuration per LED instance * Support multiple Boblight clients with different priorities * Update changelog * Simplify isGUI rules allowing for QT only builds * Sysinfo: Fix indents * LED-Devices: Show warning, if get properties failed * Qt-Grabber: Fixed position handling of multiple monitors * LED layout: Remove indention limitations * Yeelight: Test YLTD003 * hyperion-remote: Provide image filename to muxer/UI * Refactor PriorityMuxer and related * Temp: Build under Windows 2019 * Yeelight: Remove YLTD003 as it is not working without additional changes * Test Windows-latest with out removing redistributables/new MSVC * correct workflows * correct CI script * Build Windows with Qt 5.15.2 * Priority Muxer: Updates after testing * Fix Typo * Update BGHandler * QTGrabber - Reactivate windows code to avoid cursor issues * Emit prioritiesChanged when autoselect was changed by user Co-authored-by: Paulchen Panther <Paulchen-Panter@protonmail.com>
This commit is contained in:
parent
0a3df596cf
commit
160c5d0b3a
@ -35,7 +35,7 @@ elif [[ $CI_NAME == *"mingw64_nt"* || "$CI_NAME" == 'windows_nt' ]]; then
|
||||
echo "Number of Cores $NUMBER_OF_PROCESSORS"
|
||||
mkdir build || exit 1
|
||||
cd build
|
||||
cmake -G "Visual Studio 16 2019" -A x64 -DPLATFORM=${PLATFORM} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ../ || exit 2
|
||||
cmake -G "Visual Studio 17 2022" -A x64 -DPLATFORM=${PLATFORM} -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ../ || exit 2
|
||||
cmake --build . --target package --config Release -- -nologo -v:m -maxcpucount || exit 3
|
||||
exit 0;
|
||||
exit 1 || { echo "---> Hyperion compilation failed! Abort"; exit 5; }
|
||||
|
12
.github/workflows/pull-request.yml
vendored
12
.github/workflows/pull-request.yml
vendored
@ -121,10 +121,10 @@ jobs:
|
||||
|
||||
windows:
|
||||
name: Windows
|
||||
runs-on: windows-latest
|
||||
runs-on: windows-2022
|
||||
env:
|
||||
VCINSTALLDIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC'
|
||||
QT_VERSION: 5.15.0
|
||||
VCINSTALLDIR: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC'
|
||||
QT_VERSION: 5.15.2
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
@ -159,12 +159,6 @@ jobs:
|
||||
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
||||
key: ${{ runner.os }}-chocolatey
|
||||
|
||||
- name: "Remove Redistributable"
|
||||
shell: cmd
|
||||
run: |
|
||||
MsiExec.exe /passive /X{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}
|
||||
MsiExec.exe /passive /X{1D8E6291-B0D5-35EC-8441-6616F567A0F7}
|
||||
|
||||
- name: Install Python, NSIS, OpenSSL, DirectX SDK
|
||||
shell: powershell
|
||||
run: |
|
||||
|
12
.github/workflows/push-master.yml
vendored
12
.github/workflows/push-master.yml
vendored
@ -91,10 +91,10 @@ jobs:
|
||||
|
||||
windows:
|
||||
name: Windows
|
||||
runs-on: windows-latest
|
||||
runs-on: windows-2022
|
||||
env:
|
||||
VCINSTALLDIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC'
|
||||
QT_VERSION: 5.15.0
|
||||
VCINSTALLDIR: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC'
|
||||
QT_VERSION: 5.15.2
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
@ -122,12 +122,6 @@ jobs:
|
||||
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
||||
key: ${{ runner.os }}-chocolatey
|
||||
|
||||
- name: "Remove Redistributable"
|
||||
shell: cmd
|
||||
run: |
|
||||
MsiExec.exe /passive /X{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}
|
||||
MsiExec.exe /passive /X{1D8E6291-B0D5-35EC-8441-6616F567A0F7}
|
||||
|
||||
- name: Install Python, NSIS, OpenSSL, DirectX SDK
|
||||
shell: powershell
|
||||
run: |
|
||||
|
14
CHANGELOG.md
14
CHANGELOG.md
@ -12,18 +12,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Allow to build a "light" version of Hyperion, i.e. no grabbers, or services like flat-/proto buffers, boblight, CEC
|
||||
- Allow to restart Hyperion via Systray
|
||||
- LED Matrix Layout - Support vertical cabling direction (#1420)
|
||||
- Support additional Yeelight models
|
||||
- LED-Devices: Show warning, if get properties failed (Network devices: indication that network device is not reachable)
|
||||
- hyperion-remote: Show image filename in UI for images sent
|
||||
|
||||
### Changed
|
||||
|
||||
- Colors Smoothing is started in pause mode to save resources, when Hyperion starts with no active source
|
||||
- Boblight: Support multiple Boblight clients with different priorities
|
||||
- UI: Allow configuration of a Boblight server per LED-instance
|
||||
- UI: LED Layout - Removed limitations on indention
|
||||
|
||||
### Fixed
|
||||
|
||||
- Effects: Fix image URL in Matrix effect
|
||||
- Effects: Fix that start effect is stuck on UI
|
||||
- Fixes that the Led-Device output flow was interrupted, by an enabling API request on an already enabled device (#967
|
||||
- Yeelight - Workaround: Ignore error when setting music mode = off, but the music-mode is already off (#1372)
|
||||
- Standalone grabbers: Improved fps help/error text, fixed default address and port, fixed auto discovery of Hyperion server in hyperion-remote
|
||||
- Fixed Qt version override, e.g. set via QTDIR
|
||||
- Remote control UI: Treat duration=0 as endless
|
||||
- Stop Web-Browser capture when user triggers other activities
|
||||
- Treat http headers case insensitive (RFC 2616)
|
||||
- Qt-Grabber: Fixed position handling of multiple monitors (#1320, #1403)
|
||||
- Fixed: Signal detection does not switch off all instances (#1281)
|
||||
- Reworked PriorityMuxer and Sub-scriptions
|
||||
|
||||
## Removed
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h3 class="page-header"><i class="fa fa-camera fa-fw"></i><span data-i18n="main_menu_grabber_conf_token">Capturing Hardware</span></h3>
|
||||
<h3 class="page-header"><i class="fa fa-camera fa-fw"></i><span data-i18n="main_menu_instcapture_conf_token">Capturing Hardware</span></h3>
|
||||
|
||||
<div class="panel panel-default" style="border:0px;">
|
||||
<div class="panel-heading panel-instance" style="border-radius:3px; border-bottom:0px;">
|
||||
|
@ -199,14 +199,14 @@
|
||||
<label class="ltdlabel" for="ip_cl_ptl" data-i18n="conf_leds_layout_ptl">Point Top Left</label>
|
||||
</td>
|
||||
<td class="itd input-group">
|
||||
<input class="form-control ledCLconstr" id="ip_cl_ptlh" type="number" value="0" min="0" max="40" step="1"></input>
|
||||
<input class="form-control ledCLconstr" id="ip_cl_ptlh" type="number" value="0" min="0" max="100" step="1"></input>
|
||||
<div class="input-group-addon" data-i18n="edt_append_percent_h">%h</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ltd"></td>
|
||||
<td class="itd input-group">
|
||||
<input class="form-control ledCLconstr" id="ip_cl_ptlv" type="number" value="0" min="0" max="40" step="1"></input>
|
||||
<input class="form-control ledCLconstr" id="ip_cl_ptlv" type="number" value="0" min="0" max="100" step="1"></input>
|
||||
<div class="input-group-addon" data-i18n="edt_append_percent_v">%v</div>
|
||||
</td>
|
||||
</tr>
|
||||
@ -215,14 +215,14 @@
|
||||
<label class="ltdlabel" for="ip_cl_ptr" data-i18n="conf_leds_layout_ptr">Point Top Right</label>
|
||||
</td>
|
||||
<td class="itd input-group">
|
||||
<input class="form-control ledCLconstr" id="ip_cl_ptrh" type="number" value="100" min="60" max="100" step="1"></input>
|
||||
<input class="form-control ledCLconstr" id="ip_cl_ptrh" type="number" value="100" min="0" max="100" step="1"></input>
|
||||
<div class="input-group-addon" data-i18n="edt_append_percent_h">%</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ltd"></td>
|
||||
<td class="itd input-group">
|
||||
<input class="form-control ledCLconstr" id="ip_cl_ptrv" type="number" value="0" min="0" max="40" step="1"></input>
|
||||
<input class="form-control ledCLconstr" id="ip_cl_ptrv" type="number" value="0" min="0" max="100" step="1"></input>
|
||||
<div class="input-group-addon" data-i18n="edt_append_percent_v">%</div>
|
||||
</td>
|
||||
</tr>
|
||||
@ -231,14 +231,14 @@
|
||||
<label class="ltdlabel" for="ip_cl_pbr" data-i18n="conf_leds_layout_pbr">Point Bottom Right</label>
|
||||
</td>
|
||||
<td class="itd input-group">
|
||||
<input class="form-control ledCLconstr" id="ip_cl_pbrh" type="number" value="100" min="60" max="100" step="1"></input>
|
||||
<input class="form-control ledCLconstr" id="ip_cl_pbrh" type="number" value="100" min="0" max="100" step="1"></input>
|
||||
<div class="input-group-addon" data-i18n="edt_append_percent_h">%</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ltd"></td>
|
||||
<td class="itd input-group">
|
||||
<input class="form-control ledCLconstr" id="ip_cl_pbrv" type="number" value="100" min="60" max="100" step="1"></input>
|
||||
<input class="form-control ledCLconstr" id="ip_cl_pbrv" type="number" value="100" min="0" max="100" step="1"></input>
|
||||
<div class="input-group-addon" data-i18n="edt_append_percent_v">%</div>
|
||||
</td>
|
||||
</tr>
|
||||
@ -247,14 +247,14 @@
|
||||
<label class="ltdlabel" for="ip_cl_pbl" data-i18n="conf_leds_layout_pbl">Point Bottom Left</label>
|
||||
</td>
|
||||
<td class="itd input-group">
|
||||
<input class="form-control ledCLconstr" id="ip_cl_pblh" type="number" value="0" min="0" max="40" step="1"></input>
|
||||
<input class="form-control ledCLconstr" id="ip_cl_pblh" type="number" value="0" min="0" max="100" step="1"></input>
|
||||
<div class="input-group-addon" data-i18n="edt_append_percent_h">%</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="ltd"></td>
|
||||
<td class="itd input-group">
|
||||
<input class="form-control ledCLconstr" id="ip_cl_pblv" type="number" value="100" min="60" max="100" step="1"></input>
|
||||
<input class="form-control ledCLconstr" id="ip_cl_pblv" type="number" value="100" min="0" max="100" step="1"></input>
|
||||
<div class="input-group-addon" data-i18n="edt_append_percent_v">%</div>
|
||||
</td>
|
||||
</tr>
|
||||
@ -402,3 +402,4 @@
|
||||
|
||||
<script src="/js/content_leds.js"></script>
|
||||
|
||||
|
||||
|
@ -70,6 +70,14 @@
|
||||
<a class="fa fa-cog fa-fw" onclick="SwitchToMenuItem('MenuItemNetwork', 'editor_container_protoserver')" style="text-decoration: none; cursor: pointer"></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="dash_ports_boblight_row">
|
||||
<td></td>
|
||||
<td data-i18n="dashboard_infobox_label_port_boblight">proto</td>
|
||||
<td style="text-align: right; padding-right: 0">
|
||||
<span id="dash_boblightPort">unknown</span>
|
||||
<a class="fa fa-cog fa-fw" onclick="SwitchToMenuItem('MenuItemInstCapture', 'editor_container_boblightserver')" style="text-decoration: none; cursor: pointer"></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td data-i18n="dashboard_infobox_label_port_json">json</td>
|
||||
|
@ -55,6 +55,8 @@
|
||||
"conf_leds_contr_label_contrtype": "Controller type:",
|
||||
"conf_leds_device_info_log": "In case your LEDs do not work, check here for errors:",
|
||||
"conf_leds_device_intro": "Hyperion supports a lot of controllers to transmit data to your target device. Select a LED controller out of the sorted list and configure it. We have chosen the best default settings for each device.",
|
||||
"conf_leds_error_get_properties_text" : "Failed to get the device's properties. Please check the configuration items.",
|
||||
"conf_leds_error_get_properties_title" : "Device properties",
|
||||
"conf_leds_error_hwled_gt_layout": "The hardware LED count ($1) is greater than LEDs configured via layout ($2),<br>$3 {{plural:$3|LED|LEDs}} will stay black if you continue.",
|
||||
"conf_leds_error_hwled_lt_layout": "The hardware LED count ($1) is less than LEDs configured via layout ($2). <br> The number of LEDs configured in the layout must not exceed the available LEDs",
|
||||
"conf_leds_error_hwled_gt_maxled": "The hardware LED count ($1) is greater than the maximum number of LEDs supported by the device ($2). <br> The hardware LED count is set to ($3).",
|
||||
@ -99,6 +101,7 @@
|
||||
"conf_leds_layout_generatedconf": "Generated/Current LED Configuration",
|
||||
"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",
|
||||
"conf_leds_layout_ma_horiz": "Horizontal",
|
||||
"conf_leds_layout_ma_optbottomleft": "Bottom left",
|
||||
"conf_leds_layout_ma_optbottomright": "Bottom right",
|
||||
@ -185,6 +188,7 @@
|
||||
"dashboard_infobox_label_instance": "Instance:",
|
||||
"dashboard_infobox_label_latesthyp": "Latest Hyperion version:",
|
||||
"dashboard_infobox_label_platform": "Platform:",
|
||||
"dashboard_infobox_label_port_boblight": "Boblight Server:",
|
||||
"dashboard_infobox_label_port_flat": "Flatbuffer:",
|
||||
"dashboard_infobox_label_port_json": "JSON-Server:",
|
||||
"dashboard_infobox_label_port_proto": "Protobuffer:",
|
||||
|
@ -138,6 +138,13 @@ $(document).ready(function () {
|
||||
$("#dash_ports_proto_row").hide();
|
||||
}
|
||||
|
||||
if (jQuery.inArray("boblight", window.serverInfo.services) !== -1) {
|
||||
var boblightPort = window.serverConfig.boblightServer.enable ? window.serverConfig.boblightServer.port : $.i18n('general_disabled');
|
||||
$('#dash_boblightPort').html(boblightPort);
|
||||
} else {
|
||||
$("#dash_ports_boblight_row").hide();
|
||||
}
|
||||
|
||||
var jsonPort = window.serverConfig.jsonServer.port;
|
||||
$('#dash_jsonPort').html(jsonPort);
|
||||
var wsPorts = window.serverConfig.webConfig.port + ' | ' + window.serverConfig.webConfig.sslPort;
|
||||
|
@ -226,8 +226,10 @@ $(document).ready(function () {
|
||||
//Hide capture menu entries, if no grabbers are available
|
||||
if ((window.serverInfo.grabbers.screen.available.length === 0) && (window.serverInfo.grabbers.video.available.length === 0)) {
|
||||
$("#MenuItemGrabber").attr('style', 'display:none')
|
||||
if ((jQuery.inArray("boblight", window.serverInfo.services) === -1)) {
|
||||
$("#MenuItemInstCapture").attr('style', 'display:none')
|
||||
}
|
||||
}
|
||||
|
||||
//Hide effectsconfigurator menu entry, if effectengine is not available
|
||||
if (jQuery.inArray("effectengine", window.serverInfo.services) === -1) {
|
||||
|
@ -4,17 +4,40 @@ $(document).ready(function () {
|
||||
var screenGrabberAvailable = (window.serverInfo.grabbers.screen.available.length !== 0);
|
||||
var videoGrabberAvailable = (window.serverInfo.grabbers.video.available.length !== 0);
|
||||
|
||||
var BOBLIGHT_ENABLED = (jQuery.inArray("boblight", window.serverInfo.services) !== -1);
|
||||
|
||||
// update instance listing
|
||||
updateHyperionInstanceListing();
|
||||
|
||||
var conf_editor_instCapt = null;
|
||||
var conf_editor_bobl = null;
|
||||
|
||||
// Instance Capture
|
||||
|
||||
if (window.showOptHelp) {
|
||||
if (screenGrabberAvailable || videoGrabberAvailable) {
|
||||
$('#conf_cont').append(createRow('conf_cont_instCapt'));
|
||||
$('#conf_cont_instCapt').append(createOptPanel('fa-camera', $.i18n("edt_conf_instCapture_heading_title"), 'editor_container_instCapt', 'btn_submit_instCapt', ''));
|
||||
if (window.showOptHelp) {
|
||||
$('#conf_cont_instCapt').append(createHelpTable(window.schema.instCapture.properties, $.i18n("edt_conf_instCapture_heading_title")));
|
||||
}
|
||||
//boblight
|
||||
if (BOBLIGHT_ENABLED) {
|
||||
$('#conf_cont').append(createRow('conf_cont_bobl'));
|
||||
$('#conf_cont_bobl').append(createOptPanel('fa-sitemap', $.i18n("edt_conf_bobls_heading_title"), 'editor_container_boblightserver', 'btn_submit_boblightserver', ''));
|
||||
$('#conf_cont_bobl').append(createHelpTable(window.schema.boblightServer.properties, $.i18n("edt_conf_bobls_heading_title"), "boblightServerHelpPanelId"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$('#conf_cont').addClass('row');
|
||||
if (screenGrabberAvailable || videoGrabberAvailable) {
|
||||
$('#conf_cont').append(createOptPanel('fa-camera', $.i18n("edt_conf_instCapture_heading_title"), 'editor_container_instCapt', 'btn_submit_instCapt', ''));
|
||||
}
|
||||
if (BOBLIGHT_ENABLED) {
|
||||
$('#conf_cont').append(createOptPanel('fa-sitemap', $.i18n("edt_conf_bobls_heading_title"), 'editor_container_boblightserver', 'btn_submit_boblightserver', ''));
|
||||
}
|
||||
}
|
||||
|
||||
if (screenGrabberAvailable || videoGrabberAvailable) {
|
||||
|
||||
// Instance Capture
|
||||
conf_editor_instCapt = createJsonEditor('editor_container_instCapt', {
|
||||
@ -91,7 +114,6 @@ $(document).ready(function () {
|
||||
});
|
||||
|
||||
conf_editor_instCapt.watch('root.instCapture.v4lEnable', () => {
|
||||
console.log("instCapt.watch(root.instCapture.v4lEnable");
|
||||
var videoEnable = conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").getValue();
|
||||
if (videoEnable) {
|
||||
conf_editor_instCapt.getEditor("root.instCapture.v4lGrabberDevice").setValue(window.serverConfig.grabberV4L2.available_devices);
|
||||
@ -111,6 +133,55 @@ $(document).ready(function () {
|
||||
$('#btn_submit_instCapt').off().on('click', function () {
|
||||
requestWriteConfig(conf_editor_instCapt.getValue());
|
||||
});
|
||||
}
|
||||
|
||||
//boblight
|
||||
if (BOBLIGHT_ENABLED) {
|
||||
conf_editor_bobl = createJsonEditor('editor_container_boblightserver', {
|
||||
boblightServer: window.schema.boblightServer
|
||||
}, true, true);
|
||||
|
||||
conf_editor_bobl.on('ready', function () {
|
||||
var boblightServerEnable = conf_editor_bobl.getEditor("root.boblightServer.enable").getValue();
|
||||
if (!boblightServerEnable) {
|
||||
showInputOptionsForKey(conf_editor_bobl, "boblightServer", "enable", false);
|
||||
$('#boblightServerHelpPanelId').hide();
|
||||
}
|
||||
});
|
||||
|
||||
conf_editor_bobl.on('change', function () {
|
||||
conf_editor_bobl.validate().length || window.readOnlyMode ? $('#btn_submit_boblightserver').attr('disabled', true) : $('#btn_submit_boblightserver').attr('disabled', false);
|
||||
});
|
||||
|
||||
conf_editor_bobl.watch('root.boblightServer.enable', () => {
|
||||
var boblightServerEnable = conf_editor_bobl.getEditor("root.boblightServer.enable").getValue();
|
||||
if (boblightServerEnable) {
|
||||
//Make port instance specific, if port is still the default one (avoids overlap of used ports)
|
||||
var port = conf_editor_bobl.getEditor("root.boblightServer.port").getValue();
|
||||
if (port === conf_editor_bobl.schema.properties.boblightServer.properties.port.default) {
|
||||
port += parseInt(window.currentHyperionInstance);
|
||||
}
|
||||
conf_editor_bobl.getEditor("root.boblightServer.port").setValue(port);
|
||||
|
||||
showInputOptionsForKey(conf_editor_bobl, "boblightServer", "enable", true);
|
||||
$('#boblightServerHelpPanelId').show();
|
||||
} else {
|
||||
showInputOptionsForKey(conf_editor_bobl, "boblightServer", "enable", false);
|
||||
$('#boblightServerHelpPanelId').hide();
|
||||
}
|
||||
});
|
||||
|
||||
$('#btn_submit_boblightserver').off().on('click', function () {
|
||||
requestWriteConfig(conf_editor_bobl.getValue());
|
||||
});
|
||||
}
|
||||
|
||||
//create introduction
|
||||
if (window.showOptHelp) {
|
||||
if (BOBLIGHT_ENABLED) {
|
||||
createHint("intro", $.i18n('conf_network_bobl_intro'), "editor_container_boblightserver");
|
||||
}
|
||||
}
|
||||
|
||||
removeOverlay();
|
||||
});
|
||||
|
@ -277,7 +277,7 @@ function createClassicLeds() {
|
||||
aceEdt.set(finalLedArray);
|
||||
}
|
||||
|
||||
function createMatrixLayout(ledshoriz, ledsvert, cabling, start) {
|
||||
function createMatrixLayout(ledshoriz, ledsvert, cabling, start, direction) {
|
||||
// Big thank you to RanzQ (Juha Rantanen) from Github for this script
|
||||
// https://raw.githubusercontent.com/RanzQ/hyperion-audio-effects/master/matrix-config.js
|
||||
|
||||
@ -325,6 +325,20 @@ function createMatrixLayout(ledshoriz, ledsvert, cabling, start) {
|
||||
|
||||
var x, y
|
||||
|
||||
if (direction === 'vertical') {
|
||||
for (x = startX; forward && x <= endX || !forward && x >= endX; x += forward ? 1 : -1) {
|
||||
for (y = startY; downward && y <= endY || !downward && y >= endY; y += downward ? 1 : -1) {
|
||||
|
||||
addLed(x, y)
|
||||
}
|
||||
if (!parallel) {
|
||||
downward = !downward
|
||||
var tmp = startY
|
||||
startY = endY
|
||||
endY = tmp
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (y = startY; downward && y <= endY || !downward && y >= endY; y += downward ? 1 : -1) {
|
||||
for (x = startX; forward && x <= endX || !forward && x >= endX; x += forward ? 1 : -1) {
|
||||
addLed(x, y)
|
||||
@ -336,6 +350,7 @@ function createMatrixLayout(ledshoriz, ledsvert, cabling, start) {
|
||||
endX = tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return leds;
|
||||
}
|
||||
@ -348,9 +363,10 @@ function createMatrixLeds() {
|
||||
var ledshoriz = parseInt($("#ip_ma_ledshoriz").val());
|
||||
var ledsvert = parseInt($("#ip_ma_ledsvert").val());
|
||||
var cabling = $("#ip_ma_cabling").val();
|
||||
var direction = $("#ip_ma_direction").val();
|
||||
var start = $("#ip_ma_start").val();
|
||||
|
||||
nonBlacklistLedArray = createMatrixLayout(ledshoriz, ledsvert, cabling, start);
|
||||
nonBlacklistLedArray = createMatrixLayout(ledshoriz, ledsvert, cabling, start, direction);
|
||||
finalLedArray = blackListLeds(nonBlacklistLedArray, ledBlacklist);
|
||||
|
||||
createLedPreview(finalLedArray, 'matrix');
|
||||
@ -467,7 +483,63 @@ $(document).ready(function () {
|
||||
|
||||
// bind change event to all inputs
|
||||
$('.ledCLconstr').bind("change", function () {
|
||||
valValue(this.id, this.value, this.min, this.max);
|
||||
|
||||
//Ensure Values are in min/max ranges
|
||||
if ($(this).val() < $(this).attr('min') * 1) { $(this).val($(this).attr('min')); }
|
||||
if ($(this).val() > $(this).attr('max') * 1) { $(this).val($(this).attr('max')); }
|
||||
|
||||
//top/bottom and left/right must not overlap
|
||||
switch (this.id) {
|
||||
case "ip_cl_ptlh":
|
||||
var ptrh = parseInt($("#ip_cl_ptrh").val());
|
||||
if (this.value > ptrh) {
|
||||
$(this).val(ptrh);
|
||||
}
|
||||
break;
|
||||
case "ip_cl_ptrh":
|
||||
var ptlh = parseInt($("#ip_cl_ptlh").val());
|
||||
if (this.value < ptlh) {
|
||||
$(this).val(ptlh);
|
||||
}
|
||||
break;
|
||||
case "ip_cl_pblh":
|
||||
var pbrh = parseInt($("#ip_cl_pbrh").val());
|
||||
if (this.value > pbrh) {
|
||||
$(this).val(pbrh);
|
||||
}
|
||||
break;
|
||||
case "ip_cl_pbrh":
|
||||
var pblh = parseInt($("#ip_cl_pblh").val());
|
||||
if (this.value < pblh) {
|
||||
$(this).val(pblh);
|
||||
}
|
||||
break;
|
||||
case "ip_cl_ptlv":
|
||||
var pblv = parseInt($("#ip_cl_pblv").val());
|
||||
if (this.value > pblv) {
|
||||
$(this).val(pblv);
|
||||
}
|
||||
break;
|
||||
case "ip_cl_pblv":
|
||||
var ptlv = parseInt($("#ip_cl_ptlv").val());
|
||||
if (this.value < ptlv) {
|
||||
$(this).val(ptlv);
|
||||
}
|
||||
break;
|
||||
case "ip_cl_ptrv":
|
||||
var pbrv = parseInt($("#ip_cl_pbrv").val());
|
||||
if (this.value > pbrv) {
|
||||
$(this).val(pbrv);
|
||||
}
|
||||
break;
|
||||
case "ip_cl_pbrv":
|
||||
var ptrv = parseInt($("#ip_cl_ptrv").val());
|
||||
if (this.value < ptrv) {
|
||||
$(this).val(ptrv);
|
||||
}
|
||||
|
||||
default:
|
||||
}
|
||||
createClassicLeds();
|
||||
});
|
||||
|
||||
@ -1591,6 +1663,7 @@ async function getProperties_device(ledType, key, params) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
showNotification('warning', $.i18n('conf_leds_error_get_properties_text'), $.i18n('conf_leds_error_get_properties_title'))
|
||||
$('#btn_submit_controller').attr('disabled', true);
|
||||
$('#btn_test_controller').attr('disabled', true);
|
||||
}
|
||||
@ -1691,6 +1764,7 @@ function updateElements(ledType, key) {
|
||||
$("#ip_ma_ledshoriz").val(ledProperties.maxColumn);
|
||||
$("#ip_ma_ledsvert").val(ledProperties.maxRow);
|
||||
$("#ip_ma_cabling").val("parallel");
|
||||
$("#ip_ma_direction").val("horizontal");
|
||||
$("#ip_ma_start").val("top-left");
|
||||
createMatrixLeds();
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
$(document).ready(function () {
|
||||
performTranslation();
|
||||
|
||||
var BOBLIGHT_ENABLED = (jQuery.inArray("boblight", window.serverInfo.services) !== -1);
|
||||
var FORWARDER_ENABLED = (jQuery.inArray("forwarder", window.serverInfo.services) !== -1);
|
||||
var FLATBUF_SERVER_ENABLED = (jQuery.inArray("flatbuffer", window.serverInfo.services) !== -1);
|
||||
var PROTOTBUF_SERVER_ENABLED = (jQuery.inArray("protobuffer", window.serverInfo.services) !== -1);
|
||||
@ -10,7 +9,6 @@ $(document).ready(function () {
|
||||
var conf_editor_json = null;
|
||||
var conf_editor_proto = null;
|
||||
var conf_editor_fbs = null;
|
||||
var conf_editor_bobl = null;
|
||||
var conf_editor_forw = null;
|
||||
|
||||
addJsonEditorHostValidation();
|
||||
@ -40,13 +38,6 @@ $(document).ready(function () {
|
||||
$('#conf_cont_proto').append(createHelpTable(window.schema.protoServer.properties, $.i18n("edt_conf_pbs_heading_title"), "protoServerHelpPanelId"));
|
||||
}
|
||||
|
||||
//boblight
|
||||
if (BOBLIGHT_ENABLED) {
|
||||
$('#conf_cont').append(createRow('conf_cont_bobl'));
|
||||
$('#conf_cont_bobl').append(createOptPanel('fa-sitemap', $.i18n("edt_conf_bobls_heading_title"), 'editor_container_boblightserver', 'btn_submit_boblightserver', 'panel-system'));
|
||||
$('#conf_cont_bobl').append(createHelpTable(window.schema.boblightServer.properties, $.i18n("edt_conf_bobls_heading_title"), "boblightServerHelpPanelId"));
|
||||
}
|
||||
|
||||
//forwarder
|
||||
if (FORWARDER_ENABLED) {
|
||||
if (storedAccess != 'default') {
|
||||
@ -66,9 +57,6 @@ $(document).ready(function () {
|
||||
if (PROTOTBUF_SERVER_ENABLED) {
|
||||
$('#conf_cont').append(createOptPanel('fa-sitemap', $.i18n("edt_conf_pbs_heading_title"), 'editor_container_protoserver', 'btn_submit_protoserver'));
|
||||
}
|
||||
if (BOBLIGHT_ENABLED) {
|
||||
$('#conf_cont').append(createOptPanel('fa-sitemap', $.i18n("edt_conf_bobls_heading_title"), 'editor_container_boblightserver', 'btn_submit_boblightserver'));
|
||||
}
|
||||
if (FORWARDER_ENABLED) {
|
||||
$('#conf_cont').append(createOptPanel('fa-sitemap', $.i18n("edt_conf_fw_heading_title"), 'editor_container_forwarder', 'btn_submit_forwarder'));
|
||||
}
|
||||
@ -147,29 +135,6 @@ $(document).ready(function () {
|
||||
});
|
||||
}
|
||||
|
||||
//boblight
|
||||
if (BOBLIGHT_ENABLED) {
|
||||
conf_editor_bobl = createJsonEditor('editor_container_boblightserver', {
|
||||
boblightServer: window.schema.boblightServer
|
||||
}, true, true);
|
||||
|
||||
conf_editor_bobl.on('change', function () {
|
||||
var boblightServerEnable = conf_editor_bobl.getEditor("root.boblightServer.enable").getValue();
|
||||
if (boblightServerEnable) {
|
||||
showInputOptionsForKey(conf_editor_bobl, "boblightServer", "enable", true);
|
||||
$('#boblightServerHelpPanelId').show();
|
||||
} else {
|
||||
showInputOptionsForKey(conf_editor_bobl, "boblightServer", "enable", false);
|
||||
$('#boblightServerHelpPanelId').hide();
|
||||
}
|
||||
conf_editor_bobl.validate().length || window.readOnlyMode ? $('#btn_submit_boblightserver').attr('disabled', true) : $('#btn_submit_boblightserver').attr('disabled', false);
|
||||
});
|
||||
|
||||
$('#btn_submit_boblightserver').off().on('click', function () {
|
||||
requestWriteConfig(conf_editor_bobl.getValue());
|
||||
});
|
||||
}
|
||||
|
||||
//forwarder
|
||||
if (FORWARDER_ENABLED) {
|
||||
if (storedAccess != 'default') {
|
||||
@ -205,9 +170,6 @@ $(document).ready(function () {
|
||||
if (PROTOTBUF_SERVER_ENABLED) {
|
||||
createHint("intro", $.i18n('conf_network_proto_intro'), "editor_container_protoserver");
|
||||
}
|
||||
if (BOBLIGHT_ENABLED) {
|
||||
createHint("intro", $.i18n('conf_network_bobl_intro'), "editor_container_boblightserver");
|
||||
}
|
||||
if (FORWARDER_ENABLED) {
|
||||
createHint("intro", $.i18n('conf_network_forw_intro'), "editor_container_forwarder");
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ $(document).ready(function () {
|
||||
owner = $.i18n('remote_color_label_color') + ' ' + '<div style="width:18px; height:18px; border-radius:20px; margin-bottom:-4px; border:1px grey solid; background-color: rgb(' + value + '); display:inline-block" title="RGB: (' + value + ')"></div>';
|
||||
break;
|
||||
case "IMAGE":
|
||||
owner = $.i18n('remote_effects_label_picture') + ' ' + owner;
|
||||
owner = $.i18n('remote_effects_label_picture') + (owner !== undefined ? (' ' + owner): "");
|
||||
break;
|
||||
case "GRABBER":
|
||||
owner = $.i18n('general_comp_GRABBER') + ': (' + owner + ')';
|
||||
@ -153,6 +153,8 @@ $(document).ready(function () {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(duration && duration < 0))
|
||||
{
|
||||
if (duration && compId != "GRABBER" && compId != "FLATBUFSERVER" && compId != "PROTOSERVER")
|
||||
owner += '<br/><span style="font-size:80%; color:grey;">' + $.i18n('remote_input_duration') + ' ' + duration.toFixed(0) + $.i18n('edt_append_s') + '</span>';
|
||||
|
||||
@ -164,6 +166,7 @@ $(document).ready(function () {
|
||||
if (btn_type != 'default')
|
||||
$('.sstbody').append(createTableRow([origin, owner, priority, btn], false, true));
|
||||
}
|
||||
}
|
||||
var btn_auto_color = (window.serverInfo.priorities_autoselect ? "btn-success" : "btn-danger");
|
||||
var btn_auto_state = (window.serverInfo.priorities_autoselect ? "disabled" : "enabled");
|
||||
var btn_auto_text = (window.serverInfo.priorities_autoselect ? $.i18n('general_btn_on') : $.i18n('general_btn_off'));
|
||||
@ -313,6 +316,9 @@ $(document).ready(function () {
|
||||
if (getStorage('rmduration') != null) {
|
||||
$("#remote_duration").val(getStorage('rmduration'));
|
||||
duration = getStorage('rmduration');
|
||||
if (duration == 0) {
|
||||
duration = ENDLESS;
|
||||
}
|
||||
}
|
||||
|
||||
createCP('cp2', cpcolor, function (rgbT, hex) {
|
||||
@ -332,6 +338,9 @@ $(document).ready(function () {
|
||||
$("#remote_duration").off().on("change", function () {
|
||||
duration = valValue(this.id, this.value, this.min, this.max);
|
||||
setStorage('rmduration', duration);
|
||||
if (duration == 0) {
|
||||
duration = ENDLESS;
|
||||
}
|
||||
});
|
||||
|
||||
$("#effect_select").off().on("change", function (event) {
|
||||
@ -349,8 +358,9 @@ $(document).ready(function () {
|
||||
});
|
||||
|
||||
$("#remote_input_repimg").off().on("click", function () {
|
||||
if (lastImgData != "")
|
||||
if (lastImgData != "") {
|
||||
requestSetImage(lastImgData, duration, lastFileName);
|
||||
}
|
||||
});
|
||||
|
||||
$("#remote_input_img").change(function () {
|
||||
@ -380,7 +390,6 @@ $(document).ready(function () {
|
||||
// interval updates
|
||||
|
||||
$(window.hyperion).on('components-updated', function (e, comp) {
|
||||
//console.log ("components-updated", e, comp);
|
||||
updateComponent(comp);
|
||||
});
|
||||
|
||||
|
@ -359,21 +359,25 @@ function requestPriorityClear(prio)
|
||||
if(typeof prio !== 'number')
|
||||
prio = window.webPrio;
|
||||
|
||||
$(window.hyperion).trigger({type:"stopBrowerScreenCapture"});
|
||||
sendToHyperion("clear", "", '"priority":'+prio+'');
|
||||
}
|
||||
|
||||
function requestClearAll()
|
||||
{
|
||||
$(window.hyperion).trigger({type:"stopBrowerScreenCapture"});
|
||||
requestPriorityClear(-1)
|
||||
}
|
||||
|
||||
function requestPlayEffect(effectName, duration)
|
||||
{
|
||||
$(window.hyperion).trigger({type:"stopBrowerScreenCapture"});
|
||||
sendToHyperion("effect", "", '"effect":{"name":"'+effectName+'"},"priority":'+window.webPrio+',"duration":'+validateDuration(duration)+',"origin":"'+window.webOrigin+'"');
|
||||
}
|
||||
|
||||
function requestSetColor(r,g,b,duration)
|
||||
{
|
||||
$(window.hyperion).trigger({type:"stopBrowerScreenCapture"});
|
||||
sendToHyperion("color", "", '"color":['+r+','+g+','+b+'], "priority":'+window.webPrio+',"duration":'+validateDuration(duration)+',"origin":"'+window.webOrigin+'"');
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
$(document).ready( function() {
|
||||
$(document).ready(function () {
|
||||
|
||||
// check if browser supports streaming
|
||||
if(window.navigator.mediaDevices && window.navigator.mediaDevices.getDisplayMedia){
|
||||
if (window.navigator.mediaDevices && window.navigator.mediaDevices.getDisplayMedia) {
|
||||
$("#btn_streamer").toggle();
|
||||
}
|
||||
|
||||
@ -25,7 +25,6 @@ $(document).ready( function() {
|
||||
audio: false
|
||||
};
|
||||
|
||||
|
||||
async function startCapture() {
|
||||
streamActive = true;
|
||||
|
||||
@ -37,7 +36,7 @@ $(document).ready( function() {
|
||||
const track = stream.getVideoTracks()[0];
|
||||
|
||||
// listen for track ending, fires when user aborts through browser
|
||||
track.onended = function(event) {
|
||||
track.onended = function (event) {
|
||||
stopCapture();
|
||||
};
|
||||
|
||||
@ -47,7 +46,7 @@ $(document).ready( function() {
|
||||
onCapabilitiesReady(track.getSettings())
|
||||
), 500);
|
||||
});
|
||||
} catch(err) {
|
||||
} catch (err) {
|
||||
stopCapture();
|
||||
console.error("Error: " + err);
|
||||
}
|
||||
@ -71,41 +70,48 @@ $(document).ready( function() {
|
||||
|
||||
updateScrTimer(true);
|
||||
// sometimes it's null on abort
|
||||
if(videoElem.srcObject){
|
||||
if (videoElem.srcObject) {
|
||||
let tracks = videoElem.srcObject.getTracks();
|
||||
|
||||
tracks.forEach(track => track.stop());
|
||||
videoElem.srcObject = null;
|
||||
}
|
||||
requestPriorityClear(1);
|
||||
}
|
||||
|
||||
function takePicture(){
|
||||
function takePicture() {
|
||||
var context = canvasElem.getContext('2d');
|
||||
canvasElem.width = streamImageWidth;
|
||||
canvasElem.height = streamImageHeight;
|
||||
context.drawImage(videoElem, 0, 0, streamImageWidth, streamImageHeight);
|
||||
|
||||
var data = canvasElem.toDataURL('image/png').split(",")[1];
|
||||
requestSetImage(data, 2, "Streaming");
|
||||
requestSetImage(data, -1, "Streaming");
|
||||
}
|
||||
|
||||
// start or update screenshot timer
|
||||
function updateScrTimer(stop){
|
||||
function updateScrTimer(stop) {
|
||||
clearInterval(screenshotTimer)
|
||||
|
||||
if(stop === false){
|
||||
if (stop === false) {
|
||||
screenshotTimer = setInterval(() => (
|
||||
takePicture()
|
||||
), screenshotIntervalTimeMs);
|
||||
}
|
||||
}
|
||||
|
||||
$("#btn_streamer").off().on("click",function(e){
|
||||
if(!$("#btn_streamer_icon").hasClass("text-danger") && !streamActive){
|
||||
$("#btn_streamer").off().on("click", function (e) {
|
||||
if (!$("#btn_streamer_icon").hasClass("text-danger") && !streamActive) {
|
||||
startCapture();
|
||||
} else {
|
||||
stopCapture();
|
||||
}
|
||||
});
|
||||
|
||||
$(window.hyperion).on("stopBrowerScreenCapture", function (event) {
|
||||
if (streamActive) {
|
||||
stopCapture();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -304,7 +304,7 @@ function performAction() {
|
||||
h += '<button id="wiz_cc_btn_sp" class="btn btn-primary">' + $.i18n('wiz_cc_btn_switchpic') + '</button>';
|
||||
}
|
||||
else
|
||||
h += '<p>' + $.i18n('wiz_cc_lettvshowm', "gey_1, grey_2, grey_3, HGradient, VGradient") + '</p>';
|
||||
h += '<p>' + $.i18n('wiz_cc_lettvshowm', "grey_1, grey_2, grey_3, HGradient, VGradient") + '</p>';
|
||||
$('#wiz_cc_desc').html(h);
|
||||
$('#wiz_cc_btn_sp').off().on('click', function () {
|
||||
switchPicture(["VGradient", "grey_1", "grey_2", "grey_3", "HGradient"]);
|
||||
@ -1534,7 +1534,7 @@ async function discover_yeelight_lights() {
|
||||
|
||||
function assign_yeelight_lights() {
|
||||
// Model mappings, see https://www.home-assistant.io/integrations/yeelight/
|
||||
var models = ['color', 'color1', 'YLDP02YL', 'YLDP02YL', 'color2', 'YLDP06YL', 'color4', 'YLDP13YL', 'stripe', 'YLDD04YL', 'strip1', 'YLDD01YL', 'YLDD02YL'];
|
||||
var models = ['color', 'color1', 'YLDP02YL', 'YLDP02YL', 'color2', 'YLDP06YL', 'color4', 'YLDP13YL', 'color6', 'YLDP13AYL', 'colorc', "YLDP004-A", 'stripe', 'YLDD04YL', 'strip1', 'YLDD01YL', 'YLDD02YL', 'strip4', 'YLDD05YL', 'strip6', 'YLDD05YL'];
|
||||
|
||||
// If records are left for configuration
|
||||
if (Object.keys(lights).length > 0) {
|
||||
|
@ -231,12 +231,12 @@
|
||||
"pbrv" : 100
|
||||
},
|
||||
|
||||
"matrix":
|
||||
{
|
||||
"matrix": {
|
||||
"ledshoriz": 1,
|
||||
"ledsvert" : 1,
|
||||
"cabling" : "snake",
|
||||
"start" : "top-left"
|
||||
"ledsvert": 1,
|
||||
"cabling": "snake",
|
||||
"direction": "horizontal",
|
||||
"start": "top-left"
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -336,9 +336,9 @@ protected:
|
||||
bool getUserToken(QString &userToken);
|
||||
|
||||
///
|
||||
/// @brief Is a token authrized. On success this will grant acces to the API (NOT ADMIN API)
|
||||
/// @brief Is a token authorized. On success this will grant acces to the API (NOT ADMIN API)
|
||||
/// @param token The user Token
|
||||
/// @return True on succes
|
||||
/// @return True on success
|
||||
///
|
||||
bool isTokenAuthorized(const QString &token);
|
||||
|
||||
|
@ -17,6 +17,8 @@
|
||||
// AuthManager
|
||||
#include <hyperion/AuthManager.h>
|
||||
|
||||
#include <hyperion/PriorityMuxer.h>
|
||||
|
||||
class Hyperion;
|
||||
class ComponentRegister;
|
||||
class BonjourBrowserWrapper;
|
||||
@ -78,10 +80,13 @@ private slots:
|
||||
///
|
||||
void handleBonjourChange(const QMap<QString,BonjourRecord>& bRegisters);
|
||||
#endif
|
||||
|
||||
///
|
||||
/// @brief handle emits from PriorityMuxer
|
||||
/// @param currentPriority The current priority at time of emit
|
||||
/// @param activeInputs The current active input map at time of emit
|
||||
///
|
||||
void handlePriorityUpdate();
|
||||
void handlePriorityUpdate(int currentPriority, const PriorityMuxer::InputsMap& activeInputs);
|
||||
|
||||
///
|
||||
/// @brief Handle imageToLedsMapping updates
|
||||
|
@ -58,7 +58,7 @@ private slots:
|
||||
/// @brief Handle priority updates from Priority Muxer
|
||||
/// @param priority The new visible priority
|
||||
///
|
||||
void handlePriorityChanges(quint8 priority);
|
||||
void handlePriorityChanges(int priority);
|
||||
|
||||
///
|
||||
/// @brief Forward message to all json target hosts
|
||||
|
@ -20,14 +20,15 @@ public:
|
||||
, _prioMuxer(_hyperion->getMuxerInstance())
|
||||
, _isBgEffectConfigured(false)
|
||||
{
|
||||
// listen for config changes
|
||||
connect(_hyperion, &Hyperion::settingsChanged,
|
||||
[=](settings::type type, const QJsonDocument& config) { this->handleSettingsUpdate(type, config); }
|
||||
);
|
||||
|
||||
connect(_prioMuxer, &PriorityMuxer::prioritiesChanged,
|
||||
[=]() { this->handlePriorityUpdate(); }
|
||||
);
|
||||
// listen for config changes
|
||||
connect(_hyperion, &Hyperion::settingsChanged, this, [=] (settings::type type, const QJsonDocument& config) {
|
||||
this->handleSettingsUpdate(type, config);
|
||||
});
|
||||
|
||||
connect(_prioMuxer, &PriorityMuxer::prioritiesChanged, this, [=] {
|
||||
this->handlePriorityUpdate();
|
||||
});
|
||||
|
||||
// initialization
|
||||
handleSettingsUpdate(settings::BGEFFECT, _hyperion->getSetting(settings::BGEFFECT));
|
||||
@ -49,7 +50,10 @@ private slots:
|
||||
const QJsonObject& BGEffectConfig = _bgEffectConfig.object();
|
||||
#define BGCONFIG_ARRAY bgColorConfig.toArray()
|
||||
// clear background priority
|
||||
if (_hyperion->getCurrentPriority() == PriorityMuxer::BG_PRIORITY)
|
||||
{
|
||||
_hyperion->clear(PriorityMuxer::BG_PRIORITY);
|
||||
}
|
||||
// initial background effect/color
|
||||
if (BGEffectConfig["enable"].toBool(true))
|
||||
{
|
||||
@ -92,13 +96,14 @@ private slots:
|
||||
///
|
||||
void handlePriorityUpdate()
|
||||
{
|
||||
if (_prioMuxer->getCurrentPriority() != PriorityMuxer::BG_PRIORITY && _prioMuxer->hasPriority(PriorityMuxer::BG_PRIORITY))
|
||||
if (_prioMuxer->getCurrentPriority() < PriorityMuxer::BG_PRIORITY && _prioMuxer->hasPriority(PriorityMuxer::BG_PRIORITY))
|
||||
{
|
||||
Debug(Logger::getInstance("HYPERION"),"Stop background (color-) effect as it moved out of scope");
|
||||
_hyperion->clear(PriorityMuxer::BG_PRIORITY);
|
||||
}
|
||||
else if (_prioMuxer->getCurrentPriority() == PriorityMuxer::LOWEST_PRIORITY && _isBgEffectConfigured)
|
||||
{
|
||||
Debug(Logger::getInstance("HYPERION"),"Start background (color-) effect as it moved is scope");
|
||||
emit handleSettingsUpdate (settings::BGEFFECT, _bgEffectConfig);
|
||||
}
|
||||
}
|
||||
|
@ -500,7 +500,7 @@ private slots:
|
||||
/// @brief Handle the scenario when no/an input source is available
|
||||
/// @param priority Current priority
|
||||
///
|
||||
void handleSourceAvailability(const quint8& priority);
|
||||
void handleSourceAvailability(int priority);
|
||||
|
||||
private:
|
||||
friend class HyperionDaemon;
|
||||
|
@ -54,6 +54,8 @@ public:
|
||||
QString owner;
|
||||
};
|
||||
|
||||
typedef QMap<int, InputInfo> InputsMap;
|
||||
|
||||
//Foreground and Background priorities
|
||||
const static int FG_PRIORITY;
|
||||
const static int BG_PRIORITY;
|
||||
@ -62,6 +64,7 @@ public:
|
||||
const static int LOWEST_PRIORITY;
|
||||
/// Timeout used to identify a non active priority
|
||||
const static int TIMEOUT_NOT_ACTIVE_PRIO;
|
||||
const static int REMOVE_CLEARED_PRIO;
|
||||
|
||||
const static int ENDLESS;
|
||||
|
||||
@ -197,22 +200,13 @@ public:
|
||||
///
|
||||
void clearAll(bool forceClearAll=false);
|
||||
|
||||
///
|
||||
/// @brief Queue a manual push where muxer doesn't recognize them (e.g. continuous single color pushes)
|
||||
///
|
||||
void queuePush() { emit timeRunner(); }
|
||||
|
||||
signals:
|
||||
///
|
||||
/// @brief Signal which emits when a effect or color with timeout > -1 is running, once per second
|
||||
///
|
||||
void timeRunner();
|
||||
|
||||
///
|
||||
/// @brief Emits whenever the visible priority has changed
|
||||
/// @param priority The new visible priority
|
||||
///
|
||||
void visiblePriorityChanged(quint8 priority);
|
||||
void visiblePriorityChanged(int priority);
|
||||
|
||||
///
|
||||
/// @brief Emits whenever the current visible component changed
|
||||
@ -222,9 +216,13 @@ signals:
|
||||
|
||||
///
|
||||
/// @brief Emits whenever something changes which influences the priorities listing
|
||||
/// Emits also in 1s interval when a COLOR or EFFECT is running with a timeout > -1 (endless)
|
||||
|
||||
/// Emits also in 1s interval when a COLOR or EFFECT is running with a timeout > -1
|
||||
/// @param currentPriority The current priority at time of emit
|
||||
/// @param activeInputs The current active input map at time of emit
|
||||
|
||||
///
|
||||
void prioritiesChanged();
|
||||
void prioritiesChanged(int currentPriority, InputsMap activeInputs);
|
||||
|
||||
///
|
||||
/// internal used signal to resolve treading issues with timer
|
||||
@ -233,15 +231,15 @@ signals:
|
||||
|
||||
private slots:
|
||||
///
|
||||
/// Slot which is called to adapt to 1s interval for signal timeRunner() / prioritiesChanged()
|
||||
/// Slot which is called to adapt to 1s interval for signal prioritiesChanged()
|
||||
///
|
||||
void timeTrigger();
|
||||
|
||||
///
|
||||
/// Updates the current time. Channels with a configured time out will be checked and cleared if
|
||||
/// required.
|
||||
/// Updates the current priorities. Channels with a configured time out will be checked and cleared if
|
||||
/// required. Cleared priorities will be removed.
|
||||
///
|
||||
void setCurrentTime();
|
||||
void updatePriorities();
|
||||
|
||||
private:
|
||||
///
|
||||
@ -266,7 +264,7 @@ private:
|
||||
hyperion::Components _prevVisComp = hyperion::COMP_INVALID;
|
||||
|
||||
/// The mapping from priority channel to led-information
|
||||
QMap<int, InputInfo> _activeInputs;
|
||||
InputsMap _activeInputs;
|
||||
|
||||
/// The information of the lowest priority channel
|
||||
InputInfo _lowestPriorityInfo;
|
||||
|
@ -29,7 +29,7 @@ namespace NetUtils {
|
||||
server.close();
|
||||
if(port != prevPort)
|
||||
{
|
||||
Warning(log, "The requested Port '%d' was already in use, will use Port '%d' instead", prevPort, port);
|
||||
Warning(log, "The requested Port '%d' is already in use, will use Port '%d' instead", prevPort, port);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <QDateTime>
|
||||
#include <QCryptographicHash>
|
||||
#include <QImage>
|
||||
#include <QImageReader>
|
||||
#include <QBuffer>
|
||||
#include <QByteArray>
|
||||
#include <QTimer>
|
||||
@ -83,7 +84,9 @@ void API::init()
|
||||
}
|
||||
// if this is localConnection and network allows unauth locals, set authorized flag
|
||||
if (apiAuthRequired && _localConnection)
|
||||
{
|
||||
_authorized = !_authManager->isLocalAuthRequired();
|
||||
}
|
||||
|
||||
// admin access is allowed, when the connection is local and the option for local admin isn't set. Con: All local connections get full access
|
||||
if (_localConnection)
|
||||
@ -91,8 +94,10 @@ void API::init()
|
||||
_adminAuthorized = !_authManager->isLocalAdminAuthRequired();
|
||||
// just in positive direction
|
||||
if (_adminAuthorized)
|
||||
{
|
||||
_authorized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void API::setColor(int priority, const std::vector<uint8_t> &ledColors, int timeout_ms, const QString &origin, hyperion::Components callerComp)
|
||||
@ -113,12 +118,25 @@ bool API::setImage(ImageCmdData &data, hyperion::Components comp, QString &reply
|
||||
// truncate name length
|
||||
data.imgName.truncate(16);
|
||||
|
||||
if (!data.format.isEmpty())
|
||||
{
|
||||
if (data.format == "auto")
|
||||
{
|
||||
QImage img = QImage::fromData(data.data);
|
||||
data.format = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!QImageReader::supportedImageFormats().contains(data.format.toLower().toUtf8()))
|
||||
{
|
||||
replyMsg = "The given format [" + data.format + "] is not supported";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QImage img = QImage::fromData(data.data, QSTRING_CSTR(data.format));
|
||||
if (img.isNull())
|
||||
{
|
||||
replyMsg = "Failed to parse picture, the file might be corrupted";
|
||||
replyMsg = "Failed to parse picture, the file might be corrupted or content does not match the given format [" + data.format + "]";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -365,20 +365,26 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
|
||||
QJsonArray priorities;
|
||||
uint64_t now = QDateTime::currentMSecsSinceEpoch();
|
||||
QList<int> activePriorities = _hyperion->getActivePriorities();
|
||||
activePriorities.removeAll(255);
|
||||
activePriorities.removeAll(PriorityMuxer::LOWEST_PRIORITY);
|
||||
int currentPriority = _hyperion->getCurrentPriority();
|
||||
|
||||
for(int priority : activePriorities)
|
||||
for(int priority : qAsConst(activePriorities))
|
||||
{
|
||||
const Hyperion::InputInfo &priorityInfo = _hyperion->getPriorityInfo(priority);
|
||||
|
||||
QJsonObject item;
|
||||
item["priority"] = priority;
|
||||
if (priorityInfo.timeoutTime_ms > 0)
|
||||
|
||||
if (priorityInfo.timeoutTime_ms > 0 )
|
||||
{
|
||||
item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
|
||||
}
|
||||
|
||||
// owner has optional informations to the component
|
||||
if (!priorityInfo.owner.isEmpty())
|
||||
{
|
||||
item["owner"] = priorityInfo.owner;
|
||||
}
|
||||
|
||||
item["componentId"] = QString(hyperion::componentToIdString(priorityInfo.componentId));
|
||||
item["origin"] = priorityInfo.origin;
|
||||
@ -397,7 +403,8 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
|
||||
LEDcolor.insert("RGB", RGBValue);
|
||||
|
||||
uint16_t Hue;
|
||||
float Saturation, Luminace;
|
||||
float Saturation;
|
||||
float Luminace;
|
||||
|
||||
// add HSL Value to Array
|
||||
QJsonArray HSLValue;
|
||||
|
@ -44,6 +44,8 @@ JsonCB::JsonCB(QObject* parent)
|
||||
#if defined(ENABLE_EFFECTENGINE)
|
||||
_availableCommands << "effects-update";
|
||||
#endif
|
||||
|
||||
qRegisterMetaType<PriorityMuxer::InputsMap>("InputsMap");
|
||||
}
|
||||
|
||||
bool JsonCB::subscribeFor(const QString& type, bool unsubscribe)
|
||||
@ -226,25 +228,33 @@ void JsonCB::handleBonjourChange(const QMap<QString,BonjourRecord>& bRegisters)
|
||||
doCallback("sessions-update", QVariant(data));
|
||||
}
|
||||
#endif
|
||||
void JsonCB::handlePriorityUpdate()
|
||||
|
||||
void JsonCB::handlePriorityUpdate(int currentPriority, const PriorityMuxer::InputsMap& activeInputs)
|
||||
{
|
||||
QJsonObject data;
|
||||
QJsonArray priorities;
|
||||
uint64_t now = QDateTime::currentMSecsSinceEpoch();
|
||||
QList<int> activePriorities = _prioMuxer->getPriorities();
|
||||
activePriorities.removeAll(255);
|
||||
int currentPriority = _prioMuxer->getCurrentPriority();
|
||||
QList<int> activePriorities = activeInputs.keys();
|
||||
|
||||
activePriorities.removeAll(PriorityMuxer::LOWEST_PRIORITY);
|
||||
|
||||
for (int priority : qAsConst(activePriorities)) {
|
||||
|
||||
const Hyperion::InputInfo& priorityInfo = activeInputs[priority];
|
||||
|
||||
for (int priority : activePriorities) {
|
||||
const Hyperion::InputInfo priorityInfo = _prioMuxer->getInputInfo(priority);
|
||||
QJsonObject item;
|
||||
item["priority"] = priority;
|
||||
|
||||
if (priorityInfo.timeoutTime_ms > 0 )
|
||||
{
|
||||
item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
|
||||
}
|
||||
|
||||
// owner has optional informations to the component
|
||||
if(!priorityInfo.owner.isEmpty())
|
||||
{
|
||||
item["owner"] = priorityInfo.owner;
|
||||
}
|
||||
|
||||
item["componentId"] = QString(hyperion::componentToIdString(priorityInfo.componentId));
|
||||
item["origin"] = priorityInfo.origin;
|
||||
@ -263,7 +273,8 @@ void JsonCB::handlePriorityUpdate()
|
||||
LEDcolor.insert("RGB", RGBValue);
|
||||
|
||||
uint16_t Hue;
|
||||
float Saturation, Luminace;
|
||||
float Saturation;
|
||||
float Luminace;
|
||||
|
||||
// add HSL Value to Array
|
||||
QJsonArray HSLValue;
|
||||
|
@ -55,11 +55,7 @@ BoblightClientConnection::BoblightClientConnection(Hyperion* hyperion, QTcpSocke
|
||||
|
||||
BoblightClientConnection::~BoblightClientConnection()
|
||||
{
|
||||
// clear the current channel
|
||||
if (_priority != 0 && _priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
|
||||
_hyperion->clear(_priority);
|
||||
|
||||
delete _socket;
|
||||
_socket->deleteLater();
|
||||
}
|
||||
|
||||
void BoblightClientConnection::readData()
|
||||
@ -117,9 +113,10 @@ QString BoblightClientConnection::readMessage(const char* data, const size_t siz
|
||||
|
||||
void BoblightClientConnection::socketClosed()
|
||||
{
|
||||
// clear the current channel
|
||||
if (_priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
|
||||
{
|
||||
_hyperion->clear(_priority);
|
||||
}
|
||||
|
||||
emit connectionClosed(this);
|
||||
}
|
||||
@ -205,11 +202,17 @@ void BoblightClientConnection::handleMessage(const QString& message)
|
||||
{
|
||||
bool rc;
|
||||
const int prio = static_cast<int>(parseUInt(messageParts[2], &rc));
|
||||
if (rc && prio != _priority)
|
||||
if (rc)
|
||||
{
|
||||
if (_priority != 0 && _hyperion->getPriorityInfo(_priority).componentId == hyperion::COMP_BOBLIGHTSERVER)
|
||||
_hyperion->clear(_priority);
|
||||
int currentPriority = _hyperion->getCurrentPriority();
|
||||
|
||||
if (prio == currentPriority)
|
||||
{
|
||||
Error(_log, "The priority %i is already in use onther component of type [%s]", prio, componentToString(_hyperion->getPriorityInfo(currentPriority).componentId));
|
||||
_socket->close();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prio < BOBLIGHT_MIN_PRIORITY || prio > BOBLIGHT_MAX_PRIORITY)
|
||||
{
|
||||
_priority = BOBLIGHT_DEFAULT_PRIORITY;
|
||||
@ -222,23 +225,35 @@ void BoblightClientConnection::handleMessage(const QString& message)
|
||||
Warning(_log, "The priority %i is not in the priority range of [%d-%d]. Priority %i is used instead.",
|
||||
prio, BOBLIGHT_MIN_PRIORITY, BOBLIGHT_MAX_PRIORITY, _priority);
|
||||
// register new priority (previously modified)
|
||||
_hyperion->registerInput(_priority, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_socket->peerAddress().toString()));
|
||||
_hyperion->registerInput(_priority, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_clientAddress));
|
||||
}
|
||||
else
|
||||
{
|
||||
// register new priority
|
||||
_hyperion->registerInput(prio, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_socket->peerAddress().toString()));
|
||||
_hyperion->registerInput(prio, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_clientAddress));
|
||||
_priority = prio;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (messageParts[0] == "sync")
|
||||
{
|
||||
if (_priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
|
||||
{
|
||||
int currentPriority = _hyperion->getCurrentPriority();
|
||||
if ( _priority != currentPriority)
|
||||
{
|
||||
// register this connection's priority
|
||||
_hyperion->registerInput(_priority, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_clientAddress));
|
||||
}
|
||||
|
||||
if (_priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
|
||||
{
|
||||
_hyperion->setInput(_priority, _ledColors); // send current color values to hyperion
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@ -387,6 +402,14 @@ uint8_t BoblightClientConnection::parseByte(const QString& s, bool *ok) const
|
||||
return static_cast<uint8_t>(qBound(LO, int(HI * d), HI)); // qBound args are in order min, value, max; see: https://doc.qt.io/qt-5/qtglobal.html#qBound
|
||||
}
|
||||
|
||||
void BoblightClientConnection::sendMessage(const QByteArray &message)
|
||||
{
|
||||
if (_socket->isOpen())
|
||||
{
|
||||
_socket->write(message);
|
||||
}
|
||||
}
|
||||
|
||||
void BoblightClientConnection::sendLightMessage()
|
||||
{
|
||||
char buffer[256];
|
||||
|
@ -36,6 +36,13 @@ public:
|
||||
///
|
||||
~BoblightClientConnection() override;
|
||||
|
||||
///
|
||||
/// Get the Boblight client's IP-address
|
||||
///
|
||||
/// @returns IP-address as QString
|
||||
///
|
||||
QString getClientAddress() { return _clientAddress; }
|
||||
|
||||
signals:
|
||||
///
|
||||
/// Signal which is emitted when the connection is being closed
|
||||
@ -67,7 +74,7 @@ private:
|
||||
///
|
||||
/// @param message The boblight message to send
|
||||
///
|
||||
void sendMessage(const QByteArray &message) { _socket->write(message); };
|
||||
void sendMessage(const QByteArray &message);
|
||||
|
||||
///
|
||||
/// Send a lights message the to connected client
|
||||
|
@ -22,9 +22,12 @@ BoblightServer::BoblightServer(Hyperion* hyperion,const QJsonDocument& config)
|
||||
, _server(new QTcpServer(this))
|
||||
, _openConnections()
|
||||
, _priority(0)
|
||||
, _log(Logger::getInstance("BOBLIGHT"))
|
||||
, _log(nullptr)
|
||||
, _port(0)
|
||||
{
|
||||
QString subComponent = _hyperion->property("instance").toString();
|
||||
_log= Logger::getInstance("BOBLIGHT", subComponent);
|
||||
|
||||
Debug(_log, "Instance created");
|
||||
|
||||
// listen for component change
|
||||
@ -49,7 +52,7 @@ void BoblightServer::start()
|
||||
if (NetUtils::portAvailable(_port, _log))
|
||||
_server->listen(QHostAddress::Any, _port);
|
||||
|
||||
Info(_log, "Started on port %d", _port);
|
||||
Info(_log, "Started on port: %d", _port);
|
||||
|
||||
_hyperion->setNewComponentState(COMP_BOBLIGHTSERVER, _server->isListening());
|
||||
}
|
||||
@ -92,11 +95,9 @@ uint16_t BoblightServer::getPort() const
|
||||
void BoblightServer::newConnection()
|
||||
{
|
||||
QTcpSocket * socket = _server->nextPendingConnection();
|
||||
|
||||
if (socket != nullptr)
|
||||
{
|
||||
Info(_log, "new connection");
|
||||
_hyperion->registerInput(_priority, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(socket->peerAddress().toString()));
|
||||
Info(_log, "New connection from %s ", QSTRING_CSTR(QString("Boblight@%1").arg(socket->peerAddress().toString())));
|
||||
BoblightClientConnection * connection = new BoblightClientConnection(_hyperion, socket, _priority);
|
||||
_openConnections.insert(connection);
|
||||
|
||||
@ -107,7 +108,7 @@ void BoblightServer::newConnection()
|
||||
|
||||
void BoblightServer::closedConnection(BoblightClientConnection *connection)
|
||||
{
|
||||
Debug(_log, "connection closed");
|
||||
Debug(_log, "Connection closed for %s", QSTRING_CSTR(QString("Boblight@%1").arg(connection->getClientAddress())));
|
||||
_openConnections.remove(connection);
|
||||
|
||||
// schedule to delete the connection object
|
||||
|
@ -219,7 +219,7 @@ void EffectEngine::effectFinished()
|
||||
_hyperion->clear(effect->getPriority());
|
||||
}
|
||||
|
||||
Info( _log, "effect finished");
|
||||
Info( _log, "Effect [%s] finished", QSTRING_CSTR(effect->getName()));
|
||||
for (auto effectIt = _activeEffects.begin(); effectIt != _activeEffects.end(); ++effectIt)
|
||||
{
|
||||
if (*effectIt == effect)
|
||||
|
@ -127,7 +127,7 @@ void MessageForwarder::handleCompStateChangeRequest(hyperion::Components compone
|
||||
}
|
||||
}
|
||||
|
||||
void MessageForwarder::handlePriorityChanges(quint8 priority)
|
||||
void MessageForwarder::handlePriorityChanges(int priority)
|
||||
{
|
||||
const QJsonObject obj = _hyperion->getSetting(settings::NETFORWARD).object();
|
||||
if (priority != 0 && _forwarder_enabled && obj["enable"].toBool())
|
||||
|
@ -66,9 +66,9 @@ bool QtGrabber::open()
|
||||
bool QtGrabber::setupDisplay()
|
||||
{
|
||||
bool result = false;
|
||||
if ( ! open() )
|
||||
if (!open())
|
||||
{
|
||||
if ( _isWayland )
|
||||
if (_isWayland)
|
||||
{
|
||||
Error(_log, "Grabber does not work under Wayland!");
|
||||
}
|
||||
@ -80,19 +80,19 @@ bool QtGrabber::setupDisplay()
|
||||
_numberOfSDisplays = 0;
|
||||
|
||||
QScreen* primary = QGuiApplication::primaryScreen();
|
||||
QList<QScreen *> screens = QGuiApplication::screens();
|
||||
QList<QScreen*> screens = QGuiApplication::screens();
|
||||
// inject main screen at 0, if not nullptr
|
||||
if(primary != nullptr)
|
||||
if (primary != nullptr)
|
||||
{
|
||||
screens.prepend(primary);
|
||||
// remove last main screen if twice in list
|
||||
if(screens.lastIndexOf(primary) > 0)
|
||||
if (screens.lastIndexOf(primary) > 0)
|
||||
{
|
||||
screens.removeAt(screens.lastIndexOf(primary));
|
||||
}
|
||||
}
|
||||
|
||||
if(screens.isEmpty())
|
||||
if (screens.isEmpty())
|
||||
{
|
||||
Error(_log, "No displays found to capture from!");
|
||||
result = false;
|
||||
@ -101,24 +101,25 @@ bool QtGrabber::setupDisplay()
|
||||
{
|
||||
_numberOfSDisplays = screens.size();
|
||||
|
||||
Info(_log,"Available Displays:");
|
||||
Info(_log, "Available Displays:");
|
||||
int index = 0;
|
||||
for(auto * screen : qAsConst(screens))
|
||||
for (auto* screen : qAsConst(screens))
|
||||
{
|
||||
const QRect geo = screen->geometry();
|
||||
Info(_log,"Display %d: Name: %s Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit", index, QSTRING_CSTR(screen->name()), geo.left(), geo.top() ,geo.right(), geo.bottom(), screen->depth());
|
||||
Info(_log, "Display %d: Name: %s Resolution: [%dx%d], Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit", index, QSTRING_CSTR(screen->name()), geo.width(), geo.height(), geo.x(), geo.y(), geo.x() + geo.width(), geo.y() + geo.height(), screen->depth());
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
if (screens.at(0)->size() != screens.at(0)->virtualSize())
|
||||
{
|
||||
const QRect vgeo = screens.at(0)->virtualGeometry();
|
||||
Info(_log,"Display %d: Name: %s Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit", _numberOfSDisplays, "All Displays", vgeo.left(), vgeo.top() ,vgeo.right(), vgeo.bottom(), screens.at(0)->depth());
|
||||
Info(_log, "Display %d: Name: %s Resolution: [%dx%d], Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit", _numberOfSDisplays, "All Displays", vgeo.width(), vgeo.height(), vgeo.x(), vgeo.y(), vgeo.x() + vgeo.width(), vgeo.y() + vgeo.height(), screens.at(0)->depth());
|
||||
}
|
||||
|
||||
_isVirtual = false;
|
||||
// be sure the index is available
|
||||
if (_display > _numberOfSDisplays - 1 )
|
||||
if (_display > _numberOfSDisplays - 1)
|
||||
{
|
||||
|
||||
if ((screens.at(0)->size() != screens.at(0)->virtualSize()) && (_display == _numberOfSDisplays))
|
||||
@ -145,7 +146,7 @@ bool QtGrabber::setupDisplay()
|
||||
}
|
||||
else
|
||||
{
|
||||
Info(_log,"Initialized display %d", _display);
|
||||
Info(_log, "Initialized display %d", _display);
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
@ -153,9 +154,9 @@ bool QtGrabber::setupDisplay()
|
||||
return result;
|
||||
}
|
||||
|
||||
void QtGrabber::geometryChanged(const QRect &geo)
|
||||
void QtGrabber::geometryChanged(const QRect& geo)
|
||||
{
|
||||
Info(_log, "The current display changed geometry to (L,T,R,B) %d,%d,%d,%d", geo.left(), geo.top() ,geo.right(), geo.bottom());
|
||||
Info(_log, "The current display changed geometry to (L,T,R,B) %d,%d,%d,%d", geo.left(), geo.top(), geo.x() + geo.width(), geo.y() + geo.height());
|
||||
updateScreenDimensions(true);
|
||||
}
|
||||
|
||||
@ -165,8 +166,6 @@ extern QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int format = 0);
|
||||
QPixmap QtGrabber::grabWindow(quintptr window, int xIn, int yIn, int width, int height) const
|
||||
{
|
||||
QSize windowSize;
|
||||
int x = xIn;
|
||||
int y = yIn;
|
||||
HWND hwnd = reinterpret_cast<HWND>(window);
|
||||
if (hwnd)
|
||||
{
|
||||
@ -179,15 +178,13 @@ QPixmap QtGrabber::grabWindow(quintptr window, int xIn, int yIn, int width, int
|
||||
hwnd = GetDesktopWindow();
|
||||
const QRect screenGeometry = _screen->geometry();
|
||||
windowSize = screenGeometry.size();
|
||||
x += screenGeometry.x();
|
||||
y += screenGeometry.y();
|
||||
}
|
||||
|
||||
if (width < 0)
|
||||
width = windowSize.width() - x;
|
||||
width = windowSize.width() - xIn;
|
||||
|
||||
if (height < 0)
|
||||
height = windowSize.height() - y;
|
||||
height = windowSize.height() - yIn;
|
||||
|
||||
// Create and setup bitmap
|
||||
HDC display_dc = GetDC(nullptr);
|
||||
@ -197,7 +194,7 @@ QPixmap QtGrabber::grabWindow(quintptr window, int xIn, int yIn, int width, int
|
||||
|
||||
// copy data
|
||||
HDC window_dc = GetDC(hwnd);
|
||||
BitBlt(bitmap_dc, 0, 0, width, height, window_dc, x, y, SRCCOPY);
|
||||
BitBlt(bitmap_dc, 0, 0, width, height, window_dc, xIn, yIn, SRCCOPY);
|
||||
|
||||
// clean up all but bitmap
|
||||
ReleaseDC(hwnd, window_dc);
|
||||
@ -211,12 +208,12 @@ QPixmap QtGrabber::grabWindow(quintptr window, int xIn, int yIn, int width, int
|
||||
}
|
||||
#endif
|
||||
|
||||
int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
int QtGrabber::grabFrame(Image<ColorRgb>& image)
|
||||
{
|
||||
int rc = 0;
|
||||
if (_isEnabled && !_isDeviceInError)
|
||||
{
|
||||
if(_screen == nullptr)
|
||||
if (_screen == nullptr)
|
||||
{
|
||||
// reinit, this will disable capture on failure
|
||||
bool result = setupDisplay();
|
||||
@ -236,7 +233,7 @@ int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
}
|
||||
else
|
||||
{
|
||||
QImage imageFrame = originalPixmap.toImage().scaled(_calculatedWidth, _calculatedHeight).convertToFormat( QImage::Format_RGB888);
|
||||
QImage imageFrame = originalPixmap.toImage().scaled(_calculatedWidth, _calculatedHeight).convertToFormat(QImage::Format_RGB888);
|
||||
image.resize(static_cast<uint>(_calculatedWidth), static_cast<uint>(_calculatedHeight));
|
||||
|
||||
for (int y = 0; y < imageFrame.height(); y++)
|
||||
@ -251,7 +248,7 @@ int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
|
||||
int QtGrabber::updateScreenDimensions(bool force)
|
||||
{
|
||||
if(_screen == nullptr)
|
||||
if (_screen == nullptr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@ -276,8 +273,8 @@ int QtGrabber::updateScreenDimensions(bool force)
|
||||
_width = geo.width();
|
||||
_height = geo.height();
|
||||
|
||||
int width=0;
|
||||
int height=0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
// Image scaling is performed by Qt
|
||||
width = (_width > (_cropLeft + _cropRight))
|
||||
@ -288,23 +285,33 @@ int QtGrabber::updateScreenDimensions(bool force)
|
||||
? ((_height - _cropTop - _cropBottom) / _pixelDecimation)
|
||||
: (_height / _pixelDecimation);
|
||||
|
||||
|
||||
// calculate final image dimensions and adjust top/left cropping in 3D modes
|
||||
if (_isVirtual)
|
||||
{
|
||||
_src_x = geo.x();
|
||||
_src_y = geo.y();
|
||||
}
|
||||
else
|
||||
{
|
||||
_src_x = 0;
|
||||
_src_y = 0;
|
||||
}
|
||||
|
||||
switch (_videoMode)
|
||||
{
|
||||
case VideoMode::VIDEO_3DSBS:
|
||||
_calculatedWidth = width /2;
|
||||
_calculatedWidth = width / 2;
|
||||
_calculatedHeight = height;
|
||||
_src_x = _cropLeft / 2;
|
||||
_src_y = _cropTop;
|
||||
_src_x = _src_x + (_cropLeft / 2);
|
||||
_src_y = _src_y + _cropTop;
|
||||
_src_x_max = (_width / 2) - _cropRight - _cropLeft;
|
||||
_src_y_max = _height - _cropBottom - _cropTop;
|
||||
break;
|
||||
case VideoMode::VIDEO_3DTAB:
|
||||
_calculatedWidth = width;
|
||||
_calculatedHeight = height / 2;
|
||||
_src_x = _cropLeft;
|
||||
_src_y = _cropTop / 2;
|
||||
_src_x = _src_x + _cropLeft;
|
||||
_src_y = _src_y + (_cropTop / 2);
|
||||
_src_x_max = _width - _cropRight - _cropLeft;
|
||||
_src_y_max = (_height / 2) - _cropBottom - _cropTop;
|
||||
break;
|
||||
@ -312,14 +319,16 @@ int QtGrabber::updateScreenDimensions(bool force)
|
||||
default:
|
||||
_calculatedWidth = width;
|
||||
_calculatedHeight = height;
|
||||
_src_x = _cropLeft;
|
||||
_src_y = _cropTop;
|
||||
_src_x = _src_x + _cropLeft;
|
||||
_src_y = _src_y + _cropTop;
|
||||
_src_x_max = _width - _cropRight - _cropLeft;
|
||||
_src_y_max = _height - _cropBottom - _cropTop;
|
||||
break;
|
||||
}
|
||||
|
||||
Info(_log, "Update output image resolution to [%dx%d]", _calculatedWidth, _calculatedHeight);
|
||||
Debug(_log, "Grab screen area: %d,%d,%d,%d", _src_x, _src_y, _src_x_max, _src_y_max);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -331,10 +340,10 @@ void QtGrabber::setVideoMode(VideoMode mode)
|
||||
|
||||
bool QtGrabber::setPixelDecimation(int pixelDecimation)
|
||||
{
|
||||
bool rc (true);
|
||||
if(Grabber::setPixelDecimation(pixelDecimation))
|
||||
bool rc(true);
|
||||
if (Grabber::setPixelDecimation(pixelDecimation))
|
||||
{
|
||||
if ( updateScreenDimensions(true) < 0)
|
||||
if (updateScreenDimensions(true) < 0)
|
||||
{
|
||||
rc = false;
|
||||
}
|
||||
@ -350,14 +359,20 @@ void QtGrabber::setCropping(int cropLeft, int cropRight, int cropTop, int cropBo
|
||||
|
||||
bool QtGrabber::setDisplayIndex(int index)
|
||||
{
|
||||
bool rc (true);
|
||||
if (_display != index)
|
||||
bool rc(true);
|
||||
if (_display != index || _isVirtual)
|
||||
{
|
||||
_isVirtual = false;
|
||||
if (index <= _numberOfSDisplays)
|
||||
{
|
||||
_display = index;
|
||||
if (index == _numberOfSDisplays)
|
||||
{
|
||||
_isVirtual = true;
|
||||
}
|
||||
else {
|
||||
}
|
||||
else
|
||||
{
|
||||
_display = 0;
|
||||
}
|
||||
rc = setupDisplay();
|
||||
@ -370,7 +385,7 @@ QJsonObject QtGrabber::discover(const QJsonObject& params)
|
||||
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
QJsonObject inputsDiscovered;
|
||||
if ( open() )
|
||||
if (open())
|
||||
{
|
||||
QList<QScreen*> screens = QGuiApplication::screens();
|
||||
if (!screens.isEmpty())
|
||||
@ -390,7 +405,7 @@ QJsonObject QtGrabber::discover(const QJsonObject& params)
|
||||
int pos = name.lastIndexOf('\\');
|
||||
if (pos != -1)
|
||||
{
|
||||
name = name.right(name.length()-pos-1);
|
||||
name = name.right(name.length() - pos - 1);
|
||||
}
|
||||
|
||||
in["name"] = name;
|
||||
@ -460,5 +475,4 @@ QJsonObject QtGrabber::discover(const QJsonObject& params)
|
||||
DebugIf(verbose, _log, "device: [%s]", QString(QJsonDocument(inputsDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
return inputsDiscovered;
|
||||
|
||||
}
|
||||
|
@ -193,7 +193,10 @@ void Hyperion::stop()
|
||||
|
||||
void Hyperion::freeObjects()
|
||||
{
|
||||
// switch off all leds
|
||||
//delete Background effect first that it does not kick in when other priorities are stopped
|
||||
delete _BGEffectHandler;
|
||||
|
||||
//Remove all priorities to switch off all leds
|
||||
clear(-1,true);
|
||||
|
||||
// delete components on exit of hyperion core
|
||||
@ -462,11 +465,6 @@ void Hyperion::setColor(int priority, const std::vector<ColorRgb> &ledColors, in
|
||||
}
|
||||
end:
|
||||
|
||||
if (getPriorityInfo(priority).componentId != hyperion::COMP_COLOR)
|
||||
{
|
||||
clear(priority);
|
||||
}
|
||||
|
||||
// register color
|
||||
registerInput(priority, hyperion::COMP_COLOR, origin);
|
||||
|
||||
@ -618,10 +616,9 @@ void Hyperion::handleVisibleComponentChanged(hyperion::Components comp)
|
||||
_raw2ledAdjustment->setBacklightEnabled((comp != hyperion::COMP_COLOR && comp != hyperion::COMP_EFFECT));
|
||||
}
|
||||
|
||||
void Hyperion::handleSourceAvailability(const quint8& priority)
|
||||
void Hyperion::handleSourceAvailability(int priority)
|
||||
{ int previousPriority = _muxer->getPreviousPriority();
|
||||
|
||||
Debug(_log,"priority[%d], previousPriority[%d]", priority, previousPriority);
|
||||
if ( priority == PriorityMuxer::LOWEST_PRIORITY)
|
||||
{
|
||||
Debug(_log,"No source left -> Pause output processing and switch LED-Device off");
|
||||
|
@ -17,6 +17,7 @@ const int PriorityMuxer::BG_PRIORITY = 254;
|
||||
const int PriorityMuxer::MANUAL_SELECTED_PRIORITY = 256;
|
||||
const int PriorityMuxer::LOWEST_PRIORITY = std::numeric_limits<uint8_t>::max();
|
||||
const int PriorityMuxer::TIMEOUT_NOT_ACTIVE_PRIO = -100;
|
||||
const int PriorityMuxer::REMOVE_CLEARED_PRIO = -101;
|
||||
const int PriorityMuxer::ENDLESS = -1;
|
||||
|
||||
PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
||||
@ -26,8 +27,6 @@ PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
||||
, _previousPriority(_currentPriority)
|
||||
, _manualSelectedPriority(MANUAL_SELECTED_PRIORITY)
|
||||
, _prevVisComp (hyperion::Components::COMP_COLOR)
|
||||
, _activeInputs()
|
||||
, _lowestPriorityInfo()
|
||||
, _sourceAutoSelectEnabled(true)
|
||||
, _updateTimer(new QTimer(this))
|
||||
, _timer(new QTimer(this))
|
||||
@ -38,8 +37,10 @@ PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
||||
|
||||
// init lowest priority info
|
||||
_lowestPriorityInfo.priority = PriorityMuxer::LOWEST_PRIORITY;
|
||||
_lowestPriorityInfo.timeoutTime_ms = PriorityMuxer::ENDLESS;
|
||||
_lowestPriorityInfo.ledColors = std::vector<ColorRgb>(ledCount, {0, 0, 0});
|
||||
|
||||
_lowestPriorityInfo.timeoutTime_ms = -1;
|
||||
_lowestPriorityInfo.ledColors = std::vector<ColorRgb>(ledCount, ColorRgb::BLACK);
|
||||
|
||||
_lowestPriorityInfo.componentId = hyperion::COMP_COLOR;
|
||||
_lowestPriorityInfo.origin = "System";
|
||||
_lowestPriorityInfo.owner = "";
|
||||
@ -50,12 +51,10 @@ PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
||||
connect(_timer, &QTimer::timeout, this, &PriorityMuxer::timeTrigger);
|
||||
_timer->setSingleShot(true);
|
||||
_blockTimer->setSingleShot(true);
|
||||
// forward timeRunner signal to prioritiesChanged signal & threading workaround
|
||||
connect(this, &PriorityMuxer::timeRunner, this, &PriorityMuxer::prioritiesChanged);
|
||||
connect(this, &PriorityMuxer::signalTimeTrigger, this, &PriorityMuxer::timeTrigger);
|
||||
|
||||
// start muxer timer
|
||||
connect(_updateTimer, &QTimer::timeout, this, &PriorityMuxer::setCurrentTime);
|
||||
connect(_updateTimer, &QTimer::timeout, this, &PriorityMuxer::updatePriorities);
|
||||
_updateTimer->setInterval(250);
|
||||
_updateTimer->start();
|
||||
}
|
||||
@ -85,7 +84,9 @@ bool PriorityMuxer::setSourceAutoSelectEnabled(bool enable, bool update)
|
||||
|
||||
// update _currentPriority if called from external
|
||||
if(update)
|
||||
setCurrentTime();
|
||||
{
|
||||
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -128,10 +129,10 @@ bool PriorityMuxer::hasPriority(int priority) const
|
||||
|
||||
PriorityMuxer::InputInfo PriorityMuxer::getInputInfo(int priority) const
|
||||
{
|
||||
auto elemIt = _activeInputs.find(priority);
|
||||
auto elemIt = _activeInputs.constFind(priority);
|
||||
if (elemIt == _activeInputs.end())
|
||||
{
|
||||
elemIt = _activeInputs.find(PriorityMuxer::LOWEST_PRIORITY);
|
||||
elemIt = _activeInputs.constFind(PriorityMuxer::LOWEST_PRIORITY);
|
||||
if (elemIt == _activeInputs.end())
|
||||
{
|
||||
// fallback
|
||||
@ -150,11 +151,18 @@ void PriorityMuxer::registerInput(int priority, hyperion::Components component,
|
||||
{
|
||||
// detect new registers
|
||||
bool newInput = false;
|
||||
bool reusedInput = false;
|
||||
|
||||
if (!_activeInputs.contains(priority))
|
||||
{
|
||||
newInput = true;
|
||||
}
|
||||
else if(_prevVisComp == component || _activeInputs[priority].componentId == component)
|
||||
reusedInput = true;
|
||||
{
|
||||
if (_activeInputs[priority].owner != owner)
|
||||
{
|
||||
newInput = true;
|
||||
}
|
||||
}
|
||||
|
||||
InputInfo& input = _activeInputs[priority];
|
||||
input.priority = priority;
|
||||
@ -166,18 +174,11 @@ void PriorityMuxer::registerInput(int priority, hyperion::Components component,
|
||||
|
||||
if (newInput)
|
||||
{
|
||||
Debug(_log,"Register new input '%s/%s' with priority %d as inactive", QSTRING_CSTR(origin), hyperion::componentToIdString(component), priority);
|
||||
// emit 'prioritiesChanged' only if _sourceAutoSelectEnabled is false
|
||||
if (!_sourceAutoSelectEnabled)
|
||||
{
|
||||
emit prioritiesChanged();
|
||||
Debug(_log,"Register new input '%s/%s' (%s) with priority %d as inactive", QSTRING_CSTR(origin), hyperion::componentToIdString(component), QSTRING_CSTR(owner), priority);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (reusedInput)
|
||||
else
|
||||
{
|
||||
emit timeRunner();
|
||||
Debug(_log,"Reuse input '%s/%s' (%s) with priority %d", QSTRING_CSTR(origin), hyperion::componentToIdString(component), QSTRING_CSTR(owner), priority);
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,12 +222,12 @@ bool PriorityMuxer::setInput(int priority, const std::vector<ColorRgb>& ledColor
|
||||
// emit active change
|
||||
if(activeChange)
|
||||
{
|
||||
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
|
||||
if (_currentPriority < priority)
|
||||
if (_currentPriority <= priority || !_sourceAutoSelectEnabled)
|
||||
{
|
||||
emit prioritiesChanged();
|
||||
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
|
||||
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||
}
|
||||
setCurrentTime();
|
||||
updatePriorities();
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -272,12 +273,12 @@ bool PriorityMuxer::setInputImage(int priority, const Image<ColorRgb>& image, in
|
||||
// emit active change
|
||||
if(activeChange)
|
||||
{
|
||||
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
|
||||
if (_currentPriority < priority)
|
||||
if (_currentPriority <= priority || !_sourceAutoSelectEnabled)
|
||||
{
|
||||
emit prioritiesChanged();
|
||||
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
|
||||
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||
}
|
||||
setCurrentTime();
|
||||
updatePriorities();
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -291,14 +292,9 @@ bool PriorityMuxer::setInputInactive(int priority)
|
||||
|
||||
bool PriorityMuxer::clearInput(int priority)
|
||||
{
|
||||
if (priority < PriorityMuxer::LOWEST_PRIORITY && (_activeInputs.remove(priority) > 0))
|
||||
if (priority < PriorityMuxer::LOWEST_PRIORITY)
|
||||
{
|
||||
Debug(_log,"Removed source priority %d",priority);
|
||||
// on clear success update _currentPriority
|
||||
setCurrentTime();
|
||||
// emit 'prioritiesChanged' only if _sourceAutoSelectEnabled is false
|
||||
if ((!_sourceAutoSelectEnabled && (_currentPriority < priority)) || _currentPriority == BG_PRIORITY)
|
||||
emit prioritiesChanged();
|
||||
_activeInputs[priority].timeoutTime_ms = REMOVE_CLEARED_PRIO;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -312,6 +308,7 @@ void PriorityMuxer::clearAll(bool forceClearAll)
|
||||
_activeInputs.clear();
|
||||
_currentPriority = PriorityMuxer::LOWEST_PRIORITY;
|
||||
_activeInputs[_currentPriority] = _lowestPriorityInfo;
|
||||
updatePriorities();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -326,35 +323,61 @@ void PriorityMuxer::clearAll(bool forceClearAll)
|
||||
}
|
||||
}
|
||||
|
||||
void PriorityMuxer::setCurrentTime()
|
||||
void PriorityMuxer::updatePriorities()
|
||||
{
|
||||
const int64_t now = QDateTime::currentMSecsSinceEpoch();
|
||||
int newPriority;
|
||||
bool priorityChanged {false};
|
||||
|
||||
_activeInputs.contains(0) ? newPriority = 0 : newPriority = PriorityMuxer::LOWEST_PRIORITY;
|
||||
|
||||
for (auto infoIt = _activeInputs.begin(); infoIt != _activeInputs.end();)
|
||||
QMutableMapIterator<int, PriorityMuxer::InputInfo> i(_activeInputs);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
|
||||
if ( i.value().timeoutTime_ms == REMOVE_CLEARED_PRIO )
|
||||
{
|
||||
if (infoIt->timeoutTime_ms > 0 && infoIt->timeoutTime_ms <= now)
|
||||
int tPrio = i.value().priority;
|
||||
i.remove();
|
||||
|
||||
Debug(_log,"Removed source priority %d", tPrio);
|
||||
priorityChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int tPrio = infoIt->priority;
|
||||
infoIt = _activeInputs.erase(infoIt);
|
||||
if (i.value().timeoutTime_ms > 0 && i.value().timeoutTime_ms <= now)
|
||||
{
|
||||
//Stop timer for deleted items to avoid additional priority update
|
||||
_timer->stop();
|
||||
int tPrio = i.value().priority;
|
||||
i.remove();
|
||||
|
||||
Debug(_log,"Timeout clear for priority %d",tPrio);
|
||||
emit prioritiesChanged();
|
||||
priorityChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// timeoutTime of TIMEOUT_NOT_ACTIVE_PRIO is awaiting data (inactive); skip
|
||||
if(infoIt->timeoutTime_ms > TIMEOUT_NOT_ACTIVE_PRIO)
|
||||
newPriority = qMin(newPriority, infoIt->priority);
|
||||
if(i.value().timeoutTime_ms > TIMEOUT_NOT_ACTIVE_PRIO)
|
||||
{
|
||||
newPriority = qMin(newPriority, i.value().priority);
|
||||
}
|
||||
|
||||
// call timeTrigger when effect or color is running with timeout > 0, blacklist prio 255
|
||||
if (infoIt->priority < BG_PRIORITY && infoIt->timeoutTime_ms > 0 && (infoIt->componentId == hyperion::COMP_EFFECT || infoIt->componentId == hyperion::COMP_COLOR || infoIt->componentId == hyperion::COMP_IMAGE))
|
||||
if (i.value().priority < BG_PRIORITY &&
|
||||
i.value().timeoutTime_ms > 0 &&
|
||||
( i.value().componentId == hyperion::COMP_EFFECT ||
|
||||
i.value().componentId == hyperion::COMP_COLOR ||
|
||||
(i.value().componentId == hyperion::COMP_IMAGE && i.value().owner != "Streaming")
|
||||
)
|
||||
)
|
||||
{
|
||||
emit signalTimeTrigger(); // as signal to prevent Threading issues
|
||||
}
|
||||
++infoIt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate, if manual selected priority is still available
|
||||
if(!_sourceAutoSelectEnabled)
|
||||
{
|
||||
@ -371,7 +394,7 @@ void PriorityMuxer::setCurrentTime()
|
||||
}
|
||||
// apply & emit on change (after apply!)
|
||||
hyperion::Components comp = getComponentOfPriority(newPriority);
|
||||
if (_currentPriority != newPriority || comp != _prevVisComp)
|
||||
if (_currentPriority != newPriority || comp != _prevVisComp )
|
||||
{
|
||||
_previousPriority = _currentPriority;
|
||||
_currentPriority = newPriority;
|
||||
@ -383,7 +406,12 @@ void PriorityMuxer::setCurrentTime()
|
||||
_prevVisComp = comp;
|
||||
emit visibleComponentChanged(comp);
|
||||
}
|
||||
emit prioritiesChanged();
|
||||
priorityChanged = true;
|
||||
}
|
||||
|
||||
if (priorityChanged)
|
||||
{
|
||||
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,7 +423,7 @@ void PriorityMuxer::timeTrigger()
|
||||
}
|
||||
else
|
||||
{
|
||||
emit timeRunner();
|
||||
_blockTimer->start(1000);
|
||||
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
"type" : "integer",
|
||||
"required" : true,
|
||||
"title" : "edt_conf_general_port_title",
|
||||
"default" : 19333,
|
||||
"minimum" : 1024,
|
||||
"maximum" : 65535,
|
||||
"propertyOrder" : 2
|
||||
|
@ -137,6 +137,10 @@
|
||||
"type": "string",
|
||||
"enum": [ "snake", "parallel" ]
|
||||
},
|
||||
"direction": {
|
||||
"type": "string",
|
||||
"enum": [ "horizontal", "vertical" ]
|
||||
},
|
||||
"start": {
|
||||
"type": "string",
|
||||
"enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ]
|
||||
|
@ -357,8 +357,10 @@ QJsonObject LedDeviceWled::getProperties(const QJsonObject& params)
|
||||
}
|
||||
|
||||
QJsonObject propertiesDetails = response.getBody().object();
|
||||
if (!propertiesDetails.isEmpty())
|
||||
{
|
||||
propertiesDetails.insert("maxLedCount", UDP_MAX_LED_NUM);
|
||||
|
||||
}
|
||||
properties.insert("properties", propertiesDetails);
|
||||
|
||||
DebugIf(verbose, _log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
@ -98,10 +98,14 @@ void QtHttpClientWrapper::onClientDataReceived (void)
|
||||
|
||||
if (pos > 0)
|
||||
{
|
||||
QByteArray header = raw.left (pos).trimmed ();
|
||||
QByteArray value = raw.mid (pos +1).trimmed ();
|
||||
QByteArray header = raw.left (pos).trimmed();
|
||||
QByteArray value = raw.mid (pos +1).trimmed();
|
||||
m_currentRequest->addHeader (header, value);
|
||||
if (header == QtHttpHeader::ContentLength)
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
||||
if (header.compare(QtHttpHeader::ContentLength, Qt::CaseInsensitive) == 0)
|
||||
#else
|
||||
if (header.toLower() == QtHttpHeader::ContentLength.toLower())
|
||||
#endif
|
||||
{
|
||||
bool ok = false;
|
||||
const int len = value.toInt (&ok, 10);
|
||||
@ -153,7 +157,7 @@ void QtHttpClientWrapper::onClientDataReceived (void)
|
||||
case RequestParsed: // a valid request has ben fully parsed
|
||||
{
|
||||
// Catch websocket header "Upgrade"
|
||||
if(m_currentRequest->getHeader(QtHttpHeader::Upgrade).toLower() == "websocket")
|
||||
if(m_currentRequest->getHeader(QtHttpHeader::Upgrade) == "websocket")
|
||||
{
|
||||
if(m_websocketClient == Q_NULLPTR)
|
||||
{
|
||||
@ -327,7 +331,7 @@ QtHttpClientWrapper::ParsingStatus QtHttpClientWrapper::sendReplyToClient (QtHtt
|
||||
{
|
||||
static const QByteArray & CLOSE = QByteArrayLiteral ("close");
|
||||
|
||||
if (m_currentRequest->getHeader (QtHttpHeader::Connection).toLower () == CLOSE)
|
||||
if (m_currentRequest->getHeader(QtHttpHeader::Connection) == CLOSE)
|
||||
{
|
||||
// must close connection after this request
|
||||
m_sockClient->close ();
|
||||
|
@ -25,7 +25,7 @@ void QtHttpRequest::setClientInfo (const QHostAddress & server, const QHostAddre
|
||||
|
||||
void QtHttpRequest::addHeader (const QByteArray & header, const QByteArray & value)
|
||||
{
|
||||
QByteArray key = header.trimmed ();
|
||||
QByteArray key = header.trimmed().toLower();
|
||||
|
||||
if (!key.isEmpty ())
|
||||
{
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
|
||||
QByteArray getHeader (const QByteArray & header) const
|
||||
{
|
||||
return m_headersHash.value (header, QByteArray ());
|
||||
return m_headersHash.value (header.toLower(), QByteArray ());
|
||||
};
|
||||
|
||||
public slots:
|
||||
|
@ -68,7 +68,7 @@ void JsonConnection::setColor(std::vector<QColor> colors, int priority, int dura
|
||||
parseReply(reply);
|
||||
}
|
||||
|
||||
void JsonConnection::setImage(QImage &image, int priority, int duration)
|
||||
void JsonConnection::setImage(QImage &image, int priority, int duration, const QString& name)
|
||||
{
|
||||
Debug(_log, "Set image has size: %dx%d", image.width(), image.height());
|
||||
|
||||
@ -93,6 +93,8 @@ void JsonConnection::setImage(QImage &image, int priority, int duration)
|
||||
command["command"] = QString("image");
|
||||
command["priority"] = priority;
|
||||
command["origin"] = QString("hyperion-remote");
|
||||
if (!name.isEmpty())
|
||||
command["name"] = name;
|
||||
command["imagewidth"] = image.width();
|
||||
command["imageheight"] = image.height();
|
||||
command["imagedata"] = QString(base64Image.data());
|
||||
|
@ -41,13 +41,14 @@ public:
|
||||
void setColor(std::vector<QColor> color, int priority, int duration);
|
||||
|
||||
///
|
||||
/// Set the leds according to the given image (assume the image is stretched to the display size)
|
||||
/// Set the LEDs according to the given image (assume the image is stretched to the display size)
|
||||
///
|
||||
/// @param image The image
|
||||
/// @param priority The priority
|
||||
/// @param duration The duration in milliseconds
|
||||
/// @param name The image's filename
|
||||
///
|
||||
void setImage(QImage &image, int priority, int duration);
|
||||
void setImage(QImage &image, int priority, int duration, const QString& name = "");
|
||||
|
||||
#if defined(ENABLE_EFFECTENGINE)
|
||||
///
|
||||
|
@ -252,7 +252,8 @@ int main(int argc, char * argv[])
|
||||
}
|
||||
else if (parser.isSet(argImage))
|
||||
{
|
||||
connection.setImage(argImage.getImage(parser), argPriority.getInt(parser), argDuration.getInt(parser));
|
||||
QFileInfo imageFile {argImage.getCString(parser)};
|
||||
connection.setImage(argImage.getImage(parser), argPriority.getInt(parser), argDuration.getInt(parser), imageFile.fileName());
|
||||
}
|
||||
#if defined(ENABLE_EFFECTENGINE)
|
||||
else if (parser.isSet(argEffect))
|
||||
|
@ -103,23 +103,7 @@ QCoreApplication* createApplication(int &argc, char *argv[])
|
||||
#else
|
||||
if (!forceNoGui)
|
||||
{
|
||||
// if x11, then test if xserver is available
|
||||
#if defined(ENABLE_X11)
|
||||
Display* dpy = XOpenDisplay(NULL);
|
||||
if (dpy != NULL)
|
||||
{
|
||||
XCloseDisplay(dpy);
|
||||
isGuiApp = true;
|
||||
}
|
||||
#elif defined(ENABLE_XCB)
|
||||
int screen_num;
|
||||
xcb_connection_t * connection = xcb_connect(nullptr, &screen_num);
|
||||
if (!xcb_connection_has_error(connection))
|
||||
{
|
||||
isGuiApp = true;
|
||||
}
|
||||
xcb_disconnect(connection);
|
||||
#endif
|
||||
isGuiApp = (getenv("DISPLAY") != NULL && (getenv("XDG_SESSION_TYPE") != NULL || getenv("WAYLAND_DISPLAY") != NULL));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -397,7 +381,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
}
|
||||
|
||||
Info(log,"Starting Hyperion - %s, %s, built: %s:%s", HYPERION_VERSION, HYPERION_BUILD_ID, __DATE__, __TIME__);
|
||||
Info(log,"Starting Hyperion [%sGUI mode] - %s, %s, built: %s:%s", isGuiApp ? "": "non-", HYPERION_VERSION, HYPERION_BUILD_ID, __DATE__, __TIME__);
|
||||
Debug(log,"QtVersion [%s]", QT_VERSION_STR);
|
||||
|
||||
if ( !readonlyMode )
|
||||
@ -423,7 +407,7 @@ int main(int argc, char** argv)
|
||||
// run the application
|
||||
if (isGuiApp)
|
||||
{
|
||||
Info(log, "start systray");
|
||||
Info(log, "Start Systray menu");
|
||||
QApplication::setQuitOnLastWindowClosed(false);
|
||||
SysTray tray(hyperiond);
|
||||
tray.hide();
|
||||
|
Loading…
Reference in New Issue
Block a user