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"
|
echo "Number of Cores $NUMBER_OF_PROCESSORS"
|
||||||
mkdir build || exit 1
|
mkdir build || exit 1
|
||||||
cd build
|
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
|
cmake --build . --target package --config Release -- -nologo -v:m -maxcpucount || exit 3
|
||||||
exit 0;
|
exit 0;
|
||||||
exit 1 || { echo "---> Hyperion compilation failed! Abort"; exit 5; }
|
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:
|
windows:
|
||||||
name: Windows
|
name: Windows
|
||||||
runs-on: windows-latest
|
runs-on: windows-2022
|
||||||
env:
|
env:
|
||||||
VCINSTALLDIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC'
|
VCINSTALLDIR: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC'
|
||||||
QT_VERSION: 5.15.0
|
QT_VERSION: 5.15.2
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
@ -159,12 +159,6 @@ jobs:
|
|||||||
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
||||||
key: ${{ runner.os }}-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
|
- name: Install Python, NSIS, OpenSSL, DirectX SDK
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
|
12
.github/workflows/push-master.yml
vendored
12
.github/workflows/push-master.yml
vendored
@ -91,10 +91,10 @@ jobs:
|
|||||||
|
|
||||||
windows:
|
windows:
|
||||||
name: Windows
|
name: Windows
|
||||||
runs-on: windows-latest
|
runs-on: windows-2022
|
||||||
env:
|
env:
|
||||||
VCINSTALLDIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC'
|
VCINSTALLDIR: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC'
|
||||||
QT_VERSION: 5.15.0
|
QT_VERSION: 5.15.2
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
@ -122,12 +122,6 @@ jobs:
|
|||||||
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
||||||
key: ${{ runner.os }}-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
|
- name: Install Python, NSIS, OpenSSL, DirectX SDK
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
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 build a "light" version of Hyperion, i.e. no grabbers, or services like flat-/proto buffers, boblight, CEC
|
||||||
- Allow to restart Hyperion via Systray
|
- 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
|
### Changed
|
||||||
|
|
||||||
- Colors Smoothing is started in pause mode to save resources, when Hyperion starts with no active source
|
- 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
|
### Fixed
|
||||||
|
|
||||||
- Effects: Fix image URL in Matrix effect
|
- 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
|
- 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)
|
- 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
|
- 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
|
- 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
|
## Removed
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<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 panel-default" style="border:0px;">
|
||||||
<div class="panel-heading panel-instance" style="border-radius:3px; border-bottom: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>
|
<label class="ltdlabel" for="ip_cl_ptl" data-i18n="conf_leds_layout_ptl">Point Top Left</label>
|
||||||
</td>
|
</td>
|
||||||
<td class="itd input-group">
|
<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>
|
<div class="input-group-addon" data-i18n="edt_append_percent_h">%h</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="ltd"></td>
|
<td class="ltd"></td>
|
||||||
<td class="itd input-group">
|
<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>
|
<div class="input-group-addon" data-i18n="edt_append_percent_v">%v</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -215,14 +215,14 @@
|
|||||||
<label class="ltdlabel" for="ip_cl_ptr" data-i18n="conf_leds_layout_ptr">Point Top Right</label>
|
<label class="ltdlabel" for="ip_cl_ptr" data-i18n="conf_leds_layout_ptr">Point Top Right</label>
|
||||||
</td>
|
</td>
|
||||||
<td class="itd input-group">
|
<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>
|
<div class="input-group-addon" data-i18n="edt_append_percent_h">%</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="ltd"></td>
|
<td class="ltd"></td>
|
||||||
<td class="itd input-group">
|
<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>
|
<div class="input-group-addon" data-i18n="edt_append_percent_v">%</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -231,14 +231,14 @@
|
|||||||
<label class="ltdlabel" for="ip_cl_pbr" data-i18n="conf_leds_layout_pbr">Point Bottom Right</label>
|
<label class="ltdlabel" for="ip_cl_pbr" data-i18n="conf_leds_layout_pbr">Point Bottom Right</label>
|
||||||
</td>
|
</td>
|
||||||
<td class="itd input-group">
|
<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>
|
<div class="input-group-addon" data-i18n="edt_append_percent_h">%</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="ltd"></td>
|
<td class="ltd"></td>
|
||||||
<td class="itd input-group">
|
<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>
|
<div class="input-group-addon" data-i18n="edt_append_percent_v">%</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -247,14 +247,14 @@
|
|||||||
<label class="ltdlabel" for="ip_cl_pbl" data-i18n="conf_leds_layout_pbl">Point Bottom Left</label>
|
<label class="ltdlabel" for="ip_cl_pbl" data-i18n="conf_leds_layout_pbl">Point Bottom Left</label>
|
||||||
</td>
|
</td>
|
||||||
<td class="itd input-group">
|
<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>
|
<div class="input-group-addon" data-i18n="edt_append_percent_h">%</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="ltd"></td>
|
<td class="ltd"></td>
|
||||||
<td class="itd input-group">
|
<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>
|
<div class="input-group-addon" data-i18n="edt_append_percent_v">%</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -402,3 +402,4 @@
|
|||||||
|
|
||||||
<script src="/js/content_leds.js"></script>
|
<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>
|
<a class="fa fa-cog fa-fw" onclick="SwitchToMenuItem('MenuItemNetwork', 'editor_container_protoserver')" style="text-decoration: none; cursor: pointer"></a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td data-i18n="dashboard_infobox_label_port_json">json</td>
|
<td data-i18n="dashboard_infobox_label_port_json">json</td>
|
||||||
|
@ -55,6 +55,8 @@
|
|||||||
"conf_leds_contr_label_contrtype": "Controller type:",
|
"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_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_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_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_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).",
|
"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_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_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_cabling": "Cabling",
|
||||||
|
"conf_leds_layout_ma_direction": "Direction",
|
||||||
"conf_leds_layout_ma_horiz": "Horizontal",
|
"conf_leds_layout_ma_horiz": "Horizontal",
|
||||||
"conf_leds_layout_ma_optbottomleft": "Bottom left",
|
"conf_leds_layout_ma_optbottomleft": "Bottom left",
|
||||||
"conf_leds_layout_ma_optbottomright": "Bottom right",
|
"conf_leds_layout_ma_optbottomright": "Bottom right",
|
||||||
@ -185,6 +188,7 @@
|
|||||||
"dashboard_infobox_label_instance": "Instance:",
|
"dashboard_infobox_label_instance": "Instance:",
|
||||||
"dashboard_infobox_label_latesthyp": "Latest Hyperion version:",
|
"dashboard_infobox_label_latesthyp": "Latest Hyperion version:",
|
||||||
"dashboard_infobox_label_platform": "Platform:",
|
"dashboard_infobox_label_platform": "Platform:",
|
||||||
|
"dashboard_infobox_label_port_boblight": "Boblight Server:",
|
||||||
"dashboard_infobox_label_port_flat": "Flatbuffer:",
|
"dashboard_infobox_label_port_flat": "Flatbuffer:",
|
||||||
"dashboard_infobox_label_port_json": "JSON-Server:",
|
"dashboard_infobox_label_port_json": "JSON-Server:",
|
||||||
"dashboard_infobox_label_port_proto": "Protobuffer:",
|
"dashboard_infobox_label_port_proto": "Protobuffer:",
|
||||||
|
@ -137,7 +137,14 @@ $(document).ready(function () {
|
|||||||
} else {
|
} else {
|
||||||
$("#dash_ports_proto_row").hide();
|
$("#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;
|
var jsonPort = window.serverConfig.jsonServer.port;
|
||||||
$('#dash_jsonPort').html(jsonPort);
|
$('#dash_jsonPort').html(jsonPort);
|
||||||
var wsPorts = window.serverConfig.webConfig.port + ' | ' + window.serverConfig.webConfig.sslPort;
|
var wsPorts = window.serverConfig.webConfig.port + ' | ' + window.serverConfig.webConfig.sslPort;
|
||||||
|
@ -226,7 +226,9 @@ $(document).ready(function () {
|
|||||||
//Hide capture menu entries, if no grabbers are available
|
//Hide capture menu entries, if no grabbers are available
|
||||||
if ((window.serverInfo.grabbers.screen.available.length === 0) && (window.serverInfo.grabbers.video.available.length === 0)) {
|
if ((window.serverInfo.grabbers.screen.available.length === 0) && (window.serverInfo.grabbers.video.available.length === 0)) {
|
||||||
$("#MenuItemGrabber").attr('style', 'display:none')
|
$("#MenuItemGrabber").attr('style', 'display:none')
|
||||||
$("#MenuItemInstCapture").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
|
//Hide effectsconfigurator menu entry, if effectengine is not available
|
||||||
|
@ -4,113 +4,184 @@ $(document).ready(function () {
|
|||||||
var screenGrabberAvailable = (window.serverInfo.grabbers.screen.available.length !== 0);
|
var screenGrabberAvailable = (window.serverInfo.grabbers.screen.available.length !== 0);
|
||||||
var videoGrabberAvailable = (window.serverInfo.grabbers.video.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
|
// update instance listing
|
||||||
updateHyperionInstanceListing();
|
updateHyperionInstanceListing();
|
||||||
|
|
||||||
var conf_editor_instCapt = null;
|
var conf_editor_instCapt = null;
|
||||||
|
var conf_editor_bobl = null;
|
||||||
|
|
||||||
// Instance Capture
|
// Instance Capture
|
||||||
$('#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) {
|
if (window.showOptHelp) {
|
||||||
$('#conf_cont_instCapt').append(createHelpTable(window.schema.instCapture.properties, $.i18n("edt_conf_instCapture_heading_title")));
|
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', ''));
|
||||||
|
$('#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', ''));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instance Capture
|
if (screenGrabberAvailable || videoGrabberAvailable) {
|
||||||
conf_editor_instCapt = createJsonEditor('editor_container_instCapt', {
|
|
||||||
instCapture: window.schema.instCapture
|
|
||||||
}, true, true);
|
|
||||||
|
|
||||||
var grabber_config_info_html = '<div class="bs-callout bs-callout-info" style="margin-top:0px"><h4>' + $.i18n('dashboard_infobox_label_title') + '</h4 >';
|
// Instance Capture
|
||||||
grabber_config_info_html += '<span>' + $.i18n('conf_grabber_inst_grabber_config_info') + '</span>';
|
conf_editor_instCapt = createJsonEditor('editor_container_instCapt', {
|
||||||
grabber_config_info_html += '<a class="fa fa-cog fa-fw" onclick="SwitchToMenuItem(\'MenuItemGrabber\')" style="text-decoration:none;cursor:pointer"></a>';
|
instCapture: window.schema.instCapture
|
||||||
grabber_config_info_html += '</div>';
|
}, true, true);
|
||||||
$('#editor_container_instCapt').append(grabber_config_info_html);
|
|
||||||
|
|
||||||
conf_editor_instCapt.on('ready', function () {
|
var grabber_config_info_html = '<div class="bs-callout bs-callout-info" style="margin-top:0px"><h4>' + $.i18n('dashboard_infobox_label_title') + '</h4 >';
|
||||||
|
grabber_config_info_html += '<span>' + $.i18n('conf_grabber_inst_grabber_config_info') + '</span>';
|
||||||
|
grabber_config_info_html += '<a class="fa fa-cog fa-fw" onclick="SwitchToMenuItem(\'MenuItemGrabber\')" style="text-decoration:none;cursor:pointer"></a>';
|
||||||
|
grabber_config_info_html += '</div>';
|
||||||
|
$('#editor_container_instCapt').append(grabber_config_info_html);
|
||||||
|
|
||||||
if (screenGrabberAvailable) {
|
conf_editor_instCapt.on('ready', function () {
|
||||||
if (!window.serverConfig.framegrabber.enable) {
|
|
||||||
conf_editor_instCapt.getEditor("root.instCapture.systemEnable").setValue(false);
|
|
||||||
conf_editor_instCapt.getEditor("root.instCapture.systemEnable").disable();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
conf_editor_instCapt.getEditor("root.instCapture.systemEnable").setValue(window.serverConfig.instCapture.systemEnable);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
showInputOptionForItem(conf_editor_instCapt, "instCapture", "systemEnable", false);
|
|
||||||
showInputOptionForItem(conf_editor_instCapt, "instCapture", "systemGrabberDevice", false);
|
|
||||||
showInputOptionForItem(conf_editor_instCapt, "instCapture", "systemPriority", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoGrabberAvailable) {
|
if (screenGrabberAvailable) {
|
||||||
if (!window.serverConfig.grabberV4L2.enable) {
|
if (!window.serverConfig.framegrabber.enable) {
|
||||||
conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").setValue(false);
|
conf_editor_instCapt.getEditor("root.instCapture.systemEnable").setValue(false);
|
||||||
conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").disable();
|
conf_editor_instCapt.getEditor("root.instCapture.systemEnable").disable();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").setValue(window.serverConfig.instCapture.v4lEnable);
|
conf_editor_instCapt.getEditor("root.instCapture.systemEnable").setValue(window.serverConfig.instCapture.systemEnable);
|
||||||
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
showInputOptionForItem(conf_editor_instCapt, "instCapture", "v4lGrabberDevice", false);
|
|
||||||
showInputOptionForItem(conf_editor_instCapt, "instCapture", "v4lEnable", false);
|
|
||||||
showInputOptionForItem(conf_editor_instCapt, "instCapture", "v4lPriority", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
conf_editor_instCapt.on('change', function () {
|
|
||||||
|
|
||||||
if (!conf_editor_instCapt.validate().length) {
|
|
||||||
if (!window.serverConfig.framegrabber.enable && !window.serverConfig.grabberV4L2.enable) {
|
|
||||||
$('#btn_submit_instCapt').attr('disabled', true);
|
|
||||||
} else {
|
} else {
|
||||||
window.readOnlyMode ? $('#btn_submit_instCapt').attr('disabled', true) : $('#btn_submit_instCapt').attr('disabled', false);
|
showInputOptionForItem(conf_editor_instCapt, "instCapture", "systemEnable", false);
|
||||||
|
showInputOptionForItem(conf_editor_instCapt, "instCapture", "systemGrabberDevice", false);
|
||||||
|
showInputOptionForItem(conf_editor_instCapt, "instCapture", "systemPriority", false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
$('#btn_submit_instCapt').attr('disabled', true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
conf_editor_instCapt.watch('root.instCapture.systemEnable', () => {
|
if (videoGrabberAvailable) {
|
||||||
|
if (!window.serverConfig.grabberV4L2.enable) {
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").setValue(false);
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").disable();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").setValue(window.serverConfig.instCapture.v4lEnable);
|
||||||
|
|
||||||
var screenEnable = conf_editor_instCapt.getEditor("root.instCapture.systemEnable").getValue();
|
}
|
||||||
if (screenEnable) {
|
} else {
|
||||||
conf_editor_instCapt.getEditor("root.instCapture.systemGrabberDevice").setValue(window.serverConfig.framegrabber.available_devices);
|
showInputOptionForItem(conf_editor_instCapt, "instCapture", "v4lGrabberDevice", false);
|
||||||
conf_editor_instCapt.getEditor("root.instCapture.systemGrabberDevice").disable();
|
showInputOptionForItem(conf_editor_instCapt, "instCapture", "v4lEnable", false);
|
||||||
showInputOptions("instCapture", ["systemGrabberDevice"], true);
|
showInputOptionForItem(conf_editor_instCapt, "instCapture", "v4lPriority", false);
|
||||||
showInputOptions("instCapture", ["systemPriority"], true);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
showInputOptions("instCapture", ["systemGrabberDevice"], false);
|
|
||||||
showInputOptions("instCapture", ["systemPriority"], false);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
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);
|
|
||||||
conf_editor_instCapt.getEditor("root.instCapture.v4lGrabberDevice").disable();
|
|
||||||
showInputOptions("instCapture", ["v4lGrabberDevice"], true);
|
|
||||||
showInputOptions("instCapture", ["v4lPriority"], true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!window.serverConfig.grabberV4L2.enable) {
|
|
||||||
conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").disable();
|
|
||||||
}
|
}
|
||||||
showInputOptions("instCapture", ["v4lGrabberDevice"], false);
|
|
||||||
showInputOptions("instCapture", ["v4lPriority"], false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#btn_submit_instCapt').off().on('click', function () {
|
});
|
||||||
requestWriteConfig(conf_editor_instCapt.getValue());
|
|
||||||
});
|
conf_editor_instCapt.on('change', function () {
|
||||||
|
|
||||||
|
if (!conf_editor_instCapt.validate().length) {
|
||||||
|
if (!window.serverConfig.framegrabber.enable && !window.serverConfig.grabberV4L2.enable) {
|
||||||
|
$('#btn_submit_instCapt').attr('disabled', true);
|
||||||
|
} else {
|
||||||
|
window.readOnlyMode ? $('#btn_submit_instCapt').attr('disabled', true) : $('#btn_submit_instCapt').attr('disabled', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#btn_submit_instCapt').attr('disabled', true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
conf_editor_instCapt.watch('root.instCapture.systemEnable', () => {
|
||||||
|
|
||||||
|
var screenEnable = conf_editor_instCapt.getEditor("root.instCapture.systemEnable").getValue();
|
||||||
|
if (screenEnable) {
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.systemGrabberDevice").setValue(window.serverConfig.framegrabber.available_devices);
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.systemGrabberDevice").disable();
|
||||||
|
showInputOptions("instCapture", ["systemGrabberDevice"], true);
|
||||||
|
showInputOptions("instCapture", ["systemPriority"], true);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
showInputOptions("instCapture", ["systemGrabberDevice"], false);
|
||||||
|
showInputOptions("instCapture", ["systemPriority"], false);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
conf_editor_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);
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.v4lGrabberDevice").disable();
|
||||||
|
showInputOptions("instCapture", ["v4lGrabberDevice"], true);
|
||||||
|
showInputOptions("instCapture", ["v4lPriority"], true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!window.serverConfig.grabberV4L2.enable) {
|
||||||
|
conf_editor_instCapt.getEditor("root.instCapture.v4lEnable").disable();
|
||||||
|
}
|
||||||
|
showInputOptions("instCapture", ["v4lGrabberDevice"], false);
|
||||||
|
showInputOptions("instCapture", ["v4lPriority"], false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#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();
|
removeOverlay();
|
||||||
});
|
});
|
||||||
|
@ -277,7 +277,7 @@ function createClassicLeds() {
|
|||||||
aceEdt.set(finalLedArray);
|
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
|
// Big thank you to RanzQ (Juha Rantanen) from Github for this script
|
||||||
// https://raw.githubusercontent.com/RanzQ/hyperion-audio-effects/master/matrix-config.js
|
// https://raw.githubusercontent.com/RanzQ/hyperion-audio-effects/master/matrix-config.js
|
||||||
|
|
||||||
@ -325,15 +325,30 @@ function createMatrixLayout(ledshoriz, ledsvert, cabling, start) {
|
|||||||
|
|
||||||
var x, y
|
var x, y
|
||||||
|
|
||||||
for (y = startY; downward && y <= endY || !downward && y >= endY; y += downward ? 1 : -1) {
|
if (direction === 'vertical') {
|
||||||
for (x = startX; forward && x <= endX || !forward && x >= endX; x += forward ? 1 : -1) {
|
for (x = startX; forward && x <= endX || !forward && x >= endX; x += forward ? 1 : -1) {
|
||||||
addLed(x, y)
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!parallel) {
|
} else {
|
||||||
forward = !forward
|
for (y = startY; downward && y <= endY || !downward && y >= endY; y += downward ? 1 : -1) {
|
||||||
var tmp = startX
|
for (x = startX; forward && x <= endX || !forward && x >= endX; x += forward ? 1 : -1) {
|
||||||
startX = endX
|
addLed(x, y)
|
||||||
endX = tmp
|
}
|
||||||
|
if (!parallel) {
|
||||||
|
forward = !forward
|
||||||
|
var tmp = startX
|
||||||
|
startX = endX
|
||||||
|
endX = tmp
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,9 +363,10 @@ function createMatrixLeds() {
|
|||||||
var ledshoriz = parseInt($("#ip_ma_ledshoriz").val());
|
var ledshoriz = parseInt($("#ip_ma_ledshoriz").val());
|
||||||
var ledsvert = parseInt($("#ip_ma_ledsvert").val());
|
var ledsvert = parseInt($("#ip_ma_ledsvert").val());
|
||||||
var cabling = $("#ip_ma_cabling").val();
|
var cabling = $("#ip_ma_cabling").val();
|
||||||
|
var direction = $("#ip_ma_direction").val();
|
||||||
var start = $("#ip_ma_start").val();
|
var start = $("#ip_ma_start").val();
|
||||||
|
|
||||||
nonBlacklistLedArray = createMatrixLayout(ledshoriz, ledsvert, cabling, start);
|
nonBlacklistLedArray = createMatrixLayout(ledshoriz, ledsvert, cabling, start, direction);
|
||||||
finalLedArray = blackListLeds(nonBlacklistLedArray, ledBlacklist);
|
finalLedArray = blackListLeds(nonBlacklistLedArray, ledBlacklist);
|
||||||
|
|
||||||
createLedPreview(finalLedArray, 'matrix');
|
createLedPreview(finalLedArray, 'matrix');
|
||||||
@ -467,7 +483,63 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
// bind change event to all inputs
|
// bind change event to all inputs
|
||||||
$('.ledCLconstr').bind("change", function () {
|
$('.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();
|
createClassicLeds();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1591,6 +1663,7 @@ async function getProperties_device(ledType, key, params) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
showNotification('warning', $.i18n('conf_leds_error_get_properties_text'), $.i18n('conf_leds_error_get_properties_title'))
|
||||||
$('#btn_submit_controller').attr('disabled', true);
|
$('#btn_submit_controller').attr('disabled', true);
|
||||||
$('#btn_test_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_ledshoriz").val(ledProperties.maxColumn);
|
||||||
$("#ip_ma_ledsvert").val(ledProperties.maxRow);
|
$("#ip_ma_ledsvert").val(ledProperties.maxRow);
|
||||||
$("#ip_ma_cabling").val("parallel");
|
$("#ip_ma_cabling").val("parallel");
|
||||||
|
$("#ip_ma_direction").val("horizontal");
|
||||||
$("#ip_ma_start").val("top-left");
|
$("#ip_ma_start").val("top-left");
|
||||||
createMatrixLeds();
|
createMatrixLeds();
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
performTranslation();
|
performTranslation();
|
||||||
|
|
||||||
var BOBLIGHT_ENABLED = (jQuery.inArray("boblight", window.serverInfo.services) !== -1);
|
|
||||||
var FORWARDER_ENABLED = (jQuery.inArray("forwarder", 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 FLATBUF_SERVER_ENABLED = (jQuery.inArray("flatbuffer", window.serverInfo.services) !== -1);
|
||||||
var PROTOTBUF_SERVER_ENABLED = (jQuery.inArray("protobuffer", 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_json = null;
|
||||||
var conf_editor_proto = null;
|
var conf_editor_proto = null;
|
||||||
var conf_editor_fbs = null;
|
var conf_editor_fbs = null;
|
||||||
var conf_editor_bobl = null;
|
|
||||||
var conf_editor_forw = null;
|
var conf_editor_forw = null;
|
||||||
|
|
||||||
addJsonEditorHostValidation();
|
addJsonEditorHostValidation();
|
||||||
@ -40,13 +38,6 @@ $(document).ready(function () {
|
|||||||
$('#conf_cont_proto').append(createHelpTable(window.schema.protoServer.properties, $.i18n("edt_conf_pbs_heading_title"), "protoServerHelpPanelId"));
|
$('#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
|
//forwarder
|
||||||
if (FORWARDER_ENABLED) {
|
if (FORWARDER_ENABLED) {
|
||||||
if (storedAccess != 'default') {
|
if (storedAccess != 'default') {
|
||||||
@ -66,9 +57,6 @@ $(document).ready(function () {
|
|||||||
if (PROTOTBUF_SERVER_ENABLED) {
|
if (PROTOTBUF_SERVER_ENABLED) {
|
||||||
$('#conf_cont').append(createOptPanel('fa-sitemap', $.i18n("edt_conf_pbs_heading_title"), 'editor_container_protoserver', 'btn_submit_protoserver'));
|
$('#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) {
|
if (FORWARDER_ENABLED) {
|
||||||
$('#conf_cont').append(createOptPanel('fa-sitemap', $.i18n("edt_conf_fw_heading_title"), 'editor_container_forwarder', 'btn_submit_forwarder'));
|
$('#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
|
//forwarder
|
||||||
if (FORWARDER_ENABLED) {
|
if (FORWARDER_ENABLED) {
|
||||||
if (storedAccess != 'default') {
|
if (storedAccess != 'default') {
|
||||||
@ -205,9 +170,6 @@ $(document).ready(function () {
|
|||||||
if (PROTOTBUF_SERVER_ENABLED) {
|
if (PROTOTBUF_SERVER_ENABLED) {
|
||||||
createHint("intro", $.i18n('conf_network_proto_intro'), "editor_container_protoserver");
|
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) {
|
if (FORWARDER_ENABLED) {
|
||||||
createHint("intro", $.i18n('conf_network_forw_intro'), "editor_container_forwarder");
|
createHint("intro", $.i18n('conf_network_forw_intro'), "editor_container_forwarder");
|
||||||
}
|
}
|
||||||
|
@ -128,13 +128,13 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
switch (compId) {
|
switch (compId) {
|
||||||
case "EFFECT":
|
case "EFFECT":
|
||||||
owner = $.i18n('remote_effects_label_effects') + ' ' + owner;
|
owner = $.i18n('remote_effects_label_effects') + ' ' + owner;
|
||||||
break;
|
break;
|
||||||
case "COLOR":
|
case "COLOR":
|
||||||
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>';
|
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;
|
break;
|
||||||
case "IMAGE":
|
case "IMAGE":
|
||||||
owner = $.i18n('remote_effects_label_picture') + ' ' + owner;
|
owner = $.i18n('remote_effects_label_picture') + (owner !== undefined ? (' ' + owner): "");
|
||||||
break;
|
break;
|
||||||
case "GRABBER":
|
case "GRABBER":
|
||||||
owner = $.i18n('general_comp_GRABBER') + ': (' + owner + ')';
|
owner = $.i18n('general_comp_GRABBER') + ': (' + owner + ')';
|
||||||
@ -153,16 +153,19 @@ $(document).ready(function () {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (duration && compId != "GRABBER" && compId != "FLATBUFSERVER" && compId != "PROTOSERVER")
|
if (!(duration && duration < 0))
|
||||||
owner += '<br/><span style="font-size:80%; color:grey;">' + $.i18n('remote_input_duration') + ' ' + duration.toFixed(0) + $.i18n('edt_append_s') + '</span>';
|
{
|
||||||
|
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>';
|
||||||
|
|
||||||
var btn = '<button id="srcBtn' + i + '" type="button" ' + btn_state + ' class="btn btn-' + btn_type + ' btn_input_selection" onclick="requestSetSource(' + priority + ');">' + btn_text + '</button>';
|
var btn = '<button id="srcBtn' + i + '" type="button" ' + btn_state + ' class="btn btn-' + btn_type + ' btn_input_selection" onclick="requestSetSource(' + priority + ');">' + btn_text + '</button>';
|
||||||
|
|
||||||
if ((compId == "EFFECT" || compId == "COLOR" || compId == "IMAGE") && priority < 254)
|
if ((compId == "EFFECT" || compId == "COLOR" || compId == "IMAGE") && priority < 254)
|
||||||
btn += '<button type="button" class="btn btn-sm btn-danger" style="margin-left:10px;" onclick="requestPriorityClear(' + priority + ');"><i class="fa fa-close"></button>';
|
btn += '<button type="button" class="btn btn-sm btn-danger" style="margin-left:10px;" onclick="requestPriorityClear(' + priority + ');"><i class="fa fa-close"></button>';
|
||||||
|
|
||||||
if (btn_type != 'default')
|
if (btn_type != 'default')
|
||||||
$('.sstbody').append(createTableRow([origin, owner, priority, btn], false, true));
|
$('.sstbody').append(createTableRow([origin, owner, priority, btn], false, true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var btn_auto_color = (window.serverInfo.priorities_autoselect ? "btn-success" : "btn-danger");
|
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_state = (window.serverInfo.priorities_autoselect ? "disabled" : "enabled");
|
||||||
@ -313,6 +316,9 @@ $(document).ready(function () {
|
|||||||
if (getStorage('rmduration') != null) {
|
if (getStorage('rmduration') != null) {
|
||||||
$("#remote_duration").val(getStorage('rmduration'));
|
$("#remote_duration").val(getStorage('rmduration'));
|
||||||
duration = getStorage('rmduration');
|
duration = getStorage('rmduration');
|
||||||
|
if (duration == 0) {
|
||||||
|
duration = ENDLESS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createCP('cp2', cpcolor, function (rgbT, hex) {
|
createCP('cp2', cpcolor, function (rgbT, hex) {
|
||||||
@ -332,6 +338,9 @@ $(document).ready(function () {
|
|||||||
$("#remote_duration").off().on("change", function () {
|
$("#remote_duration").off().on("change", function () {
|
||||||
duration = valValue(this.id, this.value, this.min, this.max);
|
duration = valValue(this.id, this.value, this.min, this.max);
|
||||||
setStorage('rmduration', duration);
|
setStorage('rmduration', duration);
|
||||||
|
if (duration == 0) {
|
||||||
|
duration = ENDLESS;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#effect_select").off().on("change", function (event) {
|
$("#effect_select").off().on("change", function (event) {
|
||||||
@ -349,8 +358,9 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$("#remote_input_repimg").off().on("click", function () {
|
$("#remote_input_repimg").off().on("click", function () {
|
||||||
if (lastImgData != "")
|
if (lastImgData != "") {
|
||||||
requestSetImage(lastImgData, duration, lastFileName);
|
requestSetImage(lastImgData, duration, lastFileName);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#remote_input_img").change(function () {
|
$("#remote_input_img").change(function () {
|
||||||
@ -380,7 +390,6 @@ $(document).ready(function () {
|
|||||||
// interval updates
|
// interval updates
|
||||||
|
|
||||||
$(window.hyperion).on('components-updated', function (e, comp) {
|
$(window.hyperion).on('components-updated', function (e, comp) {
|
||||||
//console.log ("components-updated", e, comp);
|
|
||||||
updateComponent(comp);
|
updateComponent(comp);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -359,21 +359,25 @@ function requestPriorityClear(prio)
|
|||||||
if(typeof prio !== 'number')
|
if(typeof prio !== 'number')
|
||||||
prio = window.webPrio;
|
prio = window.webPrio;
|
||||||
|
|
||||||
|
$(window.hyperion).trigger({type:"stopBrowerScreenCapture"});
|
||||||
sendToHyperion("clear", "", '"priority":'+prio+'');
|
sendToHyperion("clear", "", '"priority":'+prio+'');
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestClearAll()
|
function requestClearAll()
|
||||||
{
|
{
|
||||||
|
$(window.hyperion).trigger({type:"stopBrowerScreenCapture"});
|
||||||
requestPriorityClear(-1)
|
requestPriorityClear(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestPlayEffect(effectName, duration)
|
function requestPlayEffect(effectName, duration)
|
||||||
{
|
{
|
||||||
|
$(window.hyperion).trigger({type:"stopBrowerScreenCapture"});
|
||||||
sendToHyperion("effect", "", '"effect":{"name":"'+effectName+'"},"priority":'+window.webPrio+',"duration":'+validateDuration(duration)+',"origin":"'+window.webOrigin+'"');
|
sendToHyperion("effect", "", '"effect":{"name":"'+effectName+'"},"priority":'+window.webPrio+',"duration":'+validateDuration(duration)+',"origin":"'+window.webOrigin+'"');
|
||||||
}
|
}
|
||||||
|
|
||||||
function requestSetColor(r,g,b,duration)
|
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+'"');
|
sendToHyperion("color", "", '"color":['+r+','+g+','+b+'], "priority":'+window.webPrio+',"duration":'+validateDuration(duration)+',"origin":"'+window.webOrigin+'"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,111 +1,117 @@
|
|||||||
$(document).ready( function() {
|
$(document).ready(function () {
|
||||||
|
|
||||||
// check if browser supports streaming
|
// check if browser supports streaming
|
||||||
if(window.navigator.mediaDevices && window.navigator.mediaDevices.getDisplayMedia){
|
if (window.navigator.mediaDevices && window.navigator.mediaDevices.getDisplayMedia) {
|
||||||
$("#btn_streamer").toggle();
|
$("#btn_streamer").toggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
// variables
|
// variables
|
||||||
var streamActive = false;
|
var streamActive = false;
|
||||||
var screenshotTimer = "";
|
var screenshotTimer = "";
|
||||||
var screenshotIntervalTimeMs = 100;
|
var screenshotIntervalTimeMs = 100;
|
||||||
var streamImageHeight = 0;
|
var streamImageHeight = 0;
|
||||||
var streamImageWidth = 0;
|
var streamImageWidth = 0;
|
||||||
const videoElem = document.getElementById("streamvideo");
|
const videoElem = document.getElementById("streamvideo");
|
||||||
const canvasElem = document.getElementById("streamcanvas");
|
const canvasElem = document.getElementById("streamcanvas");
|
||||||
|
|
||||||
// Options for getDisplayMedia()
|
// Options for getDisplayMedia()
|
||||||
var displayMediaOptions = {
|
var displayMediaOptions = {
|
||||||
video: {
|
video: {
|
||||||
cursor: "never",
|
cursor: "never",
|
||||||
width: 170,
|
width: 170,
|
||||||
height: 100,
|
height: 100,
|
||||||
frameRate: 15
|
frameRate: 15
|
||||||
},
|
},
|
||||||
audio: false
|
audio: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function startCapture() {
|
||||||
|
streamActive = true;
|
||||||
|
|
||||||
async function startCapture() {
|
try {
|
||||||
streamActive = true;
|
var stream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);
|
||||||
|
videoElem.srcObject = stream;
|
||||||
|
|
||||||
try {
|
// get the active track of the stream
|
||||||
var stream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);
|
const track = stream.getVideoTracks()[0];
|
||||||
videoElem.srcObject = stream;
|
|
||||||
|
|
||||||
// get the active track of the stream
|
// listen for track ending, fires when user aborts through browser
|
||||||
const track = stream.getVideoTracks()[0];
|
track.onended = function (event) {
|
||||||
|
stopCapture();
|
||||||
|
};
|
||||||
|
|
||||||
// listen for track ending, fires when user aborts through browser
|
// wait for video ready
|
||||||
track.onended = function(event) {
|
videoElem.addEventListener('loadedmetadata', (e) => {
|
||||||
stopCapture();
|
window.setTimeout(() => (
|
||||||
};
|
onCapabilitiesReady(track.getSettings())
|
||||||
|
), 500);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
stopCapture();
|
||||||
|
console.error("Error: " + err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// wait for video ready
|
function onCapabilitiesReady(settings) {
|
||||||
videoElem.addEventListener('loadedmetadata', (e) => {
|
// extract real width/height
|
||||||
window.setTimeout(() => (
|
streamImageWidth = settings.width;
|
||||||
onCapabilitiesReady(track.getSettings())
|
streamImageHeight = settings.height;
|
||||||
), 500);
|
|
||||||
});
|
|
||||||
} catch(err) {
|
|
||||||
stopCapture();
|
|
||||||
console.error("Error: " + err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onCapabilitiesReady(settings) {
|
// start screenshotTimer
|
||||||
// extract real width/height
|
updateScrTimer(false);
|
||||||
streamImageWidth = settings.width;
|
|
||||||
streamImageHeight = settings.height;
|
|
||||||
|
|
||||||
// start screenshotTimer
|
// we are sending
|
||||||
updateScrTimer(false);
|
$("#btn_streamer_icon").addClass("text-danger");
|
||||||
|
}
|
||||||
|
|
||||||
// we are sending
|
function stopCapture(evt) {
|
||||||
$("#btn_streamer_icon").addClass("text-danger");
|
streamActive = false;
|
||||||
}
|
$("#btn_streamer_icon").removeClass("text-danger");
|
||||||
|
|
||||||
function stopCapture(evt) {
|
updateScrTimer(true);
|
||||||
streamActive = false;
|
// sometimes it's null on abort
|
||||||
$("#btn_streamer_icon").removeClass("text-danger");
|
if (videoElem.srcObject) {
|
||||||
|
let tracks = videoElem.srcObject.getTracks();
|
||||||
|
|
||||||
updateScrTimer(true);
|
tracks.forEach(track => track.stop());
|
||||||
// sometimes it's null on abort
|
videoElem.srcObject = null;
|
||||||
if(videoElem.srcObject){
|
}
|
||||||
let tracks = videoElem.srcObject.getTracks();
|
requestPriorityClear(1);
|
||||||
|
}
|
||||||
|
|
||||||
tracks.forEach(track => track.stop());
|
function takePicture() {
|
||||||
videoElem.srcObject = null;
|
var context = canvasElem.getContext('2d');
|
||||||
}
|
canvasElem.width = streamImageWidth;
|
||||||
}
|
canvasElem.height = streamImageHeight;
|
||||||
|
context.drawImage(videoElem, 0, 0, streamImageWidth, streamImageHeight);
|
||||||
|
|
||||||
function takePicture(){
|
var data = canvasElem.toDataURL('image/png').split(",")[1];
|
||||||
var context = canvasElem.getContext('2d');
|
requestSetImage(data, -1, "Streaming");
|
||||||
canvasElem.width = streamImageWidth;
|
}
|
||||||
canvasElem.height = streamImageHeight;
|
|
||||||
context.drawImage(videoElem, 0, 0, streamImageWidth, streamImageHeight);
|
|
||||||
|
|
||||||
var data = canvasElem.toDataURL('image/png').split(",")[1];
|
// start or update screenshot timer
|
||||||
requestSetImage(data, 2, "Streaming");
|
function updateScrTimer(stop) {
|
||||||
}
|
clearInterval(screenshotTimer)
|
||||||
|
|
||||||
// start or update screenshot timer
|
if (stop === false) {
|
||||||
function updateScrTimer(stop){
|
screenshotTimer = setInterval(() => (
|
||||||
clearInterval(screenshotTimer)
|
takePicture()
|
||||||
|
), screenshotIntervalTimeMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(stop === false){
|
$("#btn_streamer").off().on("click", function (e) {
|
||||||
screenshotTimer = setInterval(() => (
|
if (!$("#btn_streamer_icon").hasClass("text-danger") && !streamActive) {
|
||||||
takePicture()
|
startCapture();
|
||||||
), screenshotIntervalTimeMs);
|
} else {
|
||||||
}
|
stopCapture();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$("#btn_streamer").off().on("click",function(e){
|
$(window.hyperion).on("stopBrowerScreenCapture", function (event) {
|
||||||
if(!$("#btn_streamer_icon").hasClass("text-danger") && !streamActive){
|
if (streamActive) {
|
||||||
startCapture();
|
stopCapture();
|
||||||
} else {
|
}
|
||||||
stopCapture();
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1221,13 +1221,13 @@ function getSystemInfo() {
|
|||||||
info += '- Architecture: ' + sys.architecture + '\n';
|
info += '- Architecture: ' + sys.architecture + '\n';
|
||||||
|
|
||||||
if (sys.cpuModelName)
|
if (sys.cpuModelName)
|
||||||
info += '- CPU Model: ' + sys.cpuModelName + '\n';
|
info += '- CPU Model: ' + sys.cpuModelName + '\n';
|
||||||
if (sys.cpuModelType)
|
if (sys.cpuModelType)
|
||||||
info += '- CPU Type: ' + sys.cpuModelType + '\n';
|
info += '- CPU Type: ' + sys.cpuModelType + '\n';
|
||||||
if (sys.cpuRevision)
|
if (sys.cpuRevision)
|
||||||
info += '- CPU Revision: ' + sys.cpuRevision + '\n';
|
info += '- CPU Revision: ' + sys.cpuRevision + '\n';
|
||||||
if (sys.cpuHardware)
|
if (sys.cpuHardware)
|
||||||
info += '- CPU Hardware: ' + sys.cpuHardware + '\n';
|
info += '- CPU Hardware: ' + sys.cpuHardware + '\n';
|
||||||
|
|
||||||
info += '- Kernel: ' + sys.kernelType + ' (' + sys.kernelVersion + ' (WS: ' + sys.wordSize + '))\n';
|
info += '- Kernel: ' + sys.kernelType + ' (' + sys.kernelVersion + ' (WS: ' + sys.wordSize + '))\n';
|
||||||
info += '- Root/Admin: ' + sys.isUserAdmin + '\n';
|
info += '- Root/Admin: ' + sys.isUserAdmin + '\n';
|
||||||
|
@ -304,7 +304,7 @@ function performAction() {
|
|||||||
h += '<button id="wiz_cc_btn_sp" class="btn btn-primary">' + $.i18n('wiz_cc_btn_switchpic') + '</button>';
|
h += '<button id="wiz_cc_btn_sp" class="btn btn-primary">' + $.i18n('wiz_cc_btn_switchpic') + '</button>';
|
||||||
}
|
}
|
||||||
else
|
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_desc').html(h);
|
||||||
$('#wiz_cc_btn_sp').off().on('click', function () {
|
$('#wiz_cc_btn_sp').off().on('click', function () {
|
||||||
switchPicture(["VGradient", "grey_1", "grey_2", "grey_3", "HGradient"]);
|
switchPicture(["VGradient", "grey_1", "grey_2", "grey_3", "HGradient"]);
|
||||||
@ -1534,8 +1534,8 @@ async function discover_yeelight_lights() {
|
|||||||
|
|
||||||
function assign_yeelight_lights() {
|
function assign_yeelight_lights() {
|
||||||
// Model mappings, see https://www.home-assistant.io/integrations/yeelight/
|
// 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 records are left for configuration
|
||||||
if (Object.keys(lights).length > 0) {
|
if (Object.keys(lights).length > 0) {
|
||||||
$('#wh_topcontainer').toggle(false);
|
$('#wh_topcontainer').toggle(false);
|
||||||
|
@ -231,13 +231,13 @@
|
|||||||
"pbrv" : 100
|
"pbrv" : 100
|
||||||
},
|
},
|
||||||
|
|
||||||
"matrix":
|
"matrix": {
|
||||||
{
|
|
||||||
"ledshoriz": 1,
|
"ledshoriz": 1,
|
||||||
"ledsvert" : 1,
|
"ledsvert": 1,
|
||||||
"cabling" : "snake",
|
"cabling": "snake",
|
||||||
"start" : "top-left"
|
"direction": "horizontal",
|
||||||
}
|
"start": "top-left"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"leds":
|
"leds":
|
||||||
|
@ -336,9 +336,9 @@ protected:
|
|||||||
bool getUserToken(QString &userToken);
|
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
|
/// @param token The user Token
|
||||||
/// @return True on succes
|
/// @return True on success
|
||||||
///
|
///
|
||||||
bool isTokenAuthorized(const QString &token);
|
bool isTokenAuthorized(const QString &token);
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
// AuthManager
|
// AuthManager
|
||||||
#include <hyperion/AuthManager.h>
|
#include <hyperion/AuthManager.h>
|
||||||
|
|
||||||
|
#include <hyperion/PriorityMuxer.h>
|
||||||
|
|
||||||
class Hyperion;
|
class Hyperion;
|
||||||
class ComponentRegister;
|
class ComponentRegister;
|
||||||
class BonjourBrowserWrapper;
|
class BonjourBrowserWrapper;
|
||||||
@ -78,10 +80,13 @@ private slots:
|
|||||||
///
|
///
|
||||||
void handleBonjourChange(const QMap<QString,BonjourRecord>& bRegisters);
|
void handleBonjourChange(const QMap<QString,BonjourRecord>& bRegisters);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief handle emits from PriorityMuxer
|
/// @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
|
/// @brief Handle imageToLedsMapping updates
|
||||||
|
@ -58,7 +58,7 @@ private slots:
|
|||||||
/// @brief Handle priority updates from Priority Muxer
|
/// @brief Handle priority updates from Priority Muxer
|
||||||
/// @param priority The new visible priority
|
/// @param priority The new visible priority
|
||||||
///
|
///
|
||||||
void handlePriorityChanges(quint8 priority);
|
void handlePriorityChanges(int priority);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Forward message to all json target hosts
|
/// @brief Forward message to all json target hosts
|
||||||
|
@ -20,14 +20,15 @@ public:
|
|||||||
, _prioMuxer(_hyperion->getMuxerInstance())
|
, _prioMuxer(_hyperion->getMuxerInstance())
|
||||||
, _isBgEffectConfigured(false)
|
, _isBgEffectConfigured(false)
|
||||||
{
|
{
|
||||||
// listen for config changes
|
|
||||||
connect(_hyperion, &Hyperion::settingsChanged,
|
|
||||||
[=](settings::type type, const QJsonDocument& config) { this->handleSettingsUpdate(type, config); }
|
|
||||||
);
|
|
||||||
|
|
||||||
connect(_prioMuxer, &PriorityMuxer::prioritiesChanged,
|
// listen for config changes
|
||||||
[=]() { this->handlePriorityUpdate(); }
|
connect(_hyperion, &Hyperion::settingsChanged, this, [=] (settings::type type, const QJsonDocument& config) {
|
||||||
);
|
this->handleSettingsUpdate(type, config);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(_prioMuxer, &PriorityMuxer::prioritiesChanged, this, [=] {
|
||||||
|
this->handlePriorityUpdate();
|
||||||
|
});
|
||||||
|
|
||||||
// initialization
|
// initialization
|
||||||
handleSettingsUpdate(settings::BGEFFECT, _hyperion->getSetting(settings::BGEFFECT));
|
handleSettingsUpdate(settings::BGEFFECT, _hyperion->getSetting(settings::BGEFFECT));
|
||||||
@ -49,7 +50,10 @@ private slots:
|
|||||||
const QJsonObject& BGEffectConfig = _bgEffectConfig.object();
|
const QJsonObject& BGEffectConfig = _bgEffectConfig.object();
|
||||||
#define BGCONFIG_ARRAY bgColorConfig.toArray()
|
#define BGCONFIG_ARRAY bgColorConfig.toArray()
|
||||||
// clear background priority
|
// clear background priority
|
||||||
_hyperion->clear(PriorityMuxer::BG_PRIORITY);
|
if (_hyperion->getCurrentPriority() == PriorityMuxer::BG_PRIORITY)
|
||||||
|
{
|
||||||
|
_hyperion->clear(PriorityMuxer::BG_PRIORITY);
|
||||||
|
}
|
||||||
// initial background effect/color
|
// initial background effect/color
|
||||||
if (BGEffectConfig["enable"].toBool(true))
|
if (BGEffectConfig["enable"].toBool(true))
|
||||||
{
|
{
|
||||||
@ -92,13 +96,14 @@ private slots:
|
|||||||
///
|
///
|
||||||
void handlePriorityUpdate()
|
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");
|
Debug(Logger::getInstance("HYPERION"),"Stop background (color-) effect as it moved out of scope");
|
||||||
_hyperion->clear(PriorityMuxer::BG_PRIORITY);
|
_hyperion->clear(PriorityMuxer::BG_PRIORITY);
|
||||||
}
|
}
|
||||||
else if (_prioMuxer->getCurrentPriority() == PriorityMuxer::LOWEST_PRIORITY && _isBgEffectConfigured)
|
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);
|
emit handleSettingsUpdate (settings::BGEFFECT, _bgEffectConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -500,7 +500,7 @@ private slots:
|
|||||||
/// @brief Handle the scenario when no/an input source is available
|
/// @brief Handle the scenario when no/an input source is available
|
||||||
/// @param priority Current priority
|
/// @param priority Current priority
|
||||||
///
|
///
|
||||||
void handleSourceAvailability(const quint8& priority);
|
void handleSourceAvailability(int priority);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class HyperionDaemon;
|
friend class HyperionDaemon;
|
||||||
|
@ -54,6 +54,8 @@ public:
|
|||||||
QString owner;
|
QString owner;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef QMap<int, InputInfo> InputsMap;
|
||||||
|
|
||||||
//Foreground and Background priorities
|
//Foreground and Background priorities
|
||||||
const static int FG_PRIORITY;
|
const static int FG_PRIORITY;
|
||||||
const static int BG_PRIORITY;
|
const static int BG_PRIORITY;
|
||||||
@ -62,6 +64,7 @@ public:
|
|||||||
const static int LOWEST_PRIORITY;
|
const static int LOWEST_PRIORITY;
|
||||||
/// Timeout used to identify a non active priority
|
/// Timeout used to identify a non active priority
|
||||||
const static int TIMEOUT_NOT_ACTIVE_PRIO;
|
const static int TIMEOUT_NOT_ACTIVE_PRIO;
|
||||||
|
const static int REMOVE_CLEARED_PRIO;
|
||||||
|
|
||||||
const static int ENDLESS;
|
const static int ENDLESS;
|
||||||
|
|
||||||
@ -197,22 +200,13 @@ public:
|
|||||||
///
|
///
|
||||||
void clearAll(bool forceClearAll=false);
|
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:
|
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
|
/// @brief Emits whenever the visible priority has changed
|
||||||
/// @param priority The new visible priority
|
/// @param priority The new visible priority
|
||||||
///
|
///
|
||||||
void visiblePriorityChanged(quint8 priority);
|
void visiblePriorityChanged(int priority);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Emits whenever the current visible component changed
|
/// @brief Emits whenever the current visible component changed
|
||||||
@ -222,9 +216,13 @@ signals:
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Emits whenever something changes which influences the priorities listing
|
/// @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
|
/// internal used signal to resolve treading issues with timer
|
||||||
@ -233,15 +231,15 @@ signals:
|
|||||||
|
|
||||||
private slots:
|
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();
|
void timeTrigger();
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Updates the current time. Channels with a configured time out will be checked and cleared if
|
/// Updates the current priorities. Channels with a configured time out will be checked and cleared if
|
||||||
/// required.
|
/// required. Cleared priorities will be removed.
|
||||||
///
|
///
|
||||||
void setCurrentTime();
|
void updatePriorities();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///
|
///
|
||||||
@ -266,7 +264,7 @@ private:
|
|||||||
hyperion::Components _prevVisComp = hyperion::COMP_INVALID;
|
hyperion::Components _prevVisComp = hyperion::COMP_INVALID;
|
||||||
|
|
||||||
/// The mapping from priority channel to led-information
|
/// The mapping from priority channel to led-information
|
||||||
QMap<int, InputInfo> _activeInputs;
|
InputsMap _activeInputs;
|
||||||
|
|
||||||
/// The information of the lowest priority channel
|
/// The information of the lowest priority channel
|
||||||
InputInfo _lowestPriorityInfo;
|
InputInfo _lowestPriorityInfo;
|
||||||
|
@ -29,7 +29,7 @@ namespace NetUtils {
|
|||||||
server.close();
|
server.close();
|
||||||
if(port != prevPort)
|
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 false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#include <QImageReader>
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
@ -83,15 +84,19 @@ void API::init()
|
|||||||
}
|
}
|
||||||
// if this is localConnection and network allows unauth locals, set authorized flag
|
// if this is localConnection and network allows unauth locals, set authorized flag
|
||||||
if (apiAuthRequired && _localConnection)
|
if (apiAuthRequired && _localConnection)
|
||||||
|
{
|
||||||
_authorized = !_authManager->isLocalAuthRequired();
|
_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
|
// 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)
|
if (_localConnection)
|
||||||
{
|
{
|
||||||
_adminAuthorized = !_authManager->isLocalAdminAuthRequired();
|
_adminAuthorized = !_authManager->isLocalAdminAuthRequired();
|
||||||
// just in positive direction
|
// just in positive direction
|
||||||
if (_adminAuthorized)
|
if (_adminAuthorized)
|
||||||
_authorized = true;
|
{
|
||||||
|
_authorized = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,12 +118,25 @@ bool API::setImage(ImageCmdData &data, hyperion::Components comp, QString &reply
|
|||||||
// truncate name length
|
// truncate name length
|
||||||
data.imgName.truncate(16);
|
data.imgName.truncate(16);
|
||||||
|
|
||||||
if (data.format == "auto")
|
if (!data.format.isEmpty())
|
||||||
{
|
{
|
||||||
QImage img = QImage::fromData(data.data);
|
if (data.format == "auto")
|
||||||
|
{
|
||||||
|
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())
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,20 +365,26 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
|
|||||||
QJsonArray priorities;
|
QJsonArray priorities;
|
||||||
uint64_t now = QDateTime::currentMSecsSinceEpoch();
|
uint64_t now = QDateTime::currentMSecsSinceEpoch();
|
||||||
QList<int> activePriorities = _hyperion->getActivePriorities();
|
QList<int> activePriorities = _hyperion->getActivePriorities();
|
||||||
activePriorities.removeAll(255);
|
activePriorities.removeAll(PriorityMuxer::LOWEST_PRIORITY);
|
||||||
int currentPriority = _hyperion->getCurrentPriority();
|
int currentPriority = _hyperion->getCurrentPriority();
|
||||||
|
|
||||||
for(int priority : activePriorities)
|
for(int priority : qAsConst(activePriorities))
|
||||||
{
|
{
|
||||||
const Hyperion::InputInfo &priorityInfo = _hyperion->getPriorityInfo(priority);
|
const Hyperion::InputInfo &priorityInfo = _hyperion->getPriorityInfo(priority);
|
||||||
|
|
||||||
QJsonObject item;
|
QJsonObject item;
|
||||||
item["priority"] = priority;
|
item["priority"] = priority;
|
||||||
if (priorityInfo.timeoutTime_ms > 0)
|
|
||||||
|
if (priorityInfo.timeoutTime_ms > 0 )
|
||||||
|
{
|
||||||
item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
|
item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
|
||||||
|
}
|
||||||
|
|
||||||
// owner has optional informations to the component
|
// owner has optional informations to the component
|
||||||
if (!priorityInfo.owner.isEmpty())
|
if (!priorityInfo.owner.isEmpty())
|
||||||
|
{
|
||||||
item["owner"] = priorityInfo.owner;
|
item["owner"] = priorityInfo.owner;
|
||||||
|
}
|
||||||
|
|
||||||
item["componentId"] = QString(hyperion::componentToIdString(priorityInfo.componentId));
|
item["componentId"] = QString(hyperion::componentToIdString(priorityInfo.componentId));
|
||||||
item["origin"] = priorityInfo.origin;
|
item["origin"] = priorityInfo.origin;
|
||||||
@ -397,7 +403,8 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
|
|||||||
LEDcolor.insert("RGB", RGBValue);
|
LEDcolor.insert("RGB", RGBValue);
|
||||||
|
|
||||||
uint16_t Hue;
|
uint16_t Hue;
|
||||||
float Saturation, Luminace;
|
float Saturation;
|
||||||
|
float Luminace;
|
||||||
|
|
||||||
// add HSL Value to Array
|
// add HSL Value to Array
|
||||||
QJsonArray HSLValue;
|
QJsonArray HSLValue;
|
||||||
|
@ -44,6 +44,8 @@ JsonCB::JsonCB(QObject* parent)
|
|||||||
#if defined(ENABLE_EFFECTENGINE)
|
#if defined(ENABLE_EFFECTENGINE)
|
||||||
_availableCommands << "effects-update";
|
_availableCommands << "effects-update";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
qRegisterMetaType<PriorityMuxer::InputsMap>("InputsMap");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JsonCB::subscribeFor(const QString& type, bool unsubscribe)
|
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));
|
doCallback("sessions-update", QVariant(data));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
void JsonCB::handlePriorityUpdate()
|
|
||||||
|
void JsonCB::handlePriorityUpdate(int currentPriority, const PriorityMuxer::InputsMap& activeInputs)
|
||||||
{
|
{
|
||||||
QJsonObject data;
|
QJsonObject data;
|
||||||
QJsonArray priorities;
|
QJsonArray priorities;
|
||||||
uint64_t now = QDateTime::currentMSecsSinceEpoch();
|
uint64_t now = QDateTime::currentMSecsSinceEpoch();
|
||||||
QList<int> activePriorities = _prioMuxer->getPriorities();
|
QList<int> activePriorities = activeInputs.keys();
|
||||||
activePriorities.removeAll(255);
|
|
||||||
int currentPriority = _prioMuxer->getCurrentPriority();
|
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;
|
QJsonObject item;
|
||||||
item["priority"] = priority;
|
item["priority"] = priority;
|
||||||
|
|
||||||
if (priorityInfo.timeoutTime_ms > 0 )
|
if (priorityInfo.timeoutTime_ms > 0 )
|
||||||
|
{
|
||||||
item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
|
item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
|
||||||
|
}
|
||||||
|
|
||||||
// owner has optional informations to the component
|
// owner has optional informations to the component
|
||||||
if(!priorityInfo.owner.isEmpty())
|
if(!priorityInfo.owner.isEmpty())
|
||||||
|
{
|
||||||
item["owner"] = priorityInfo.owner;
|
item["owner"] = priorityInfo.owner;
|
||||||
|
}
|
||||||
|
|
||||||
item["componentId"] = QString(hyperion::componentToIdString(priorityInfo.componentId));
|
item["componentId"] = QString(hyperion::componentToIdString(priorityInfo.componentId));
|
||||||
item["origin"] = priorityInfo.origin;
|
item["origin"] = priorityInfo.origin;
|
||||||
@ -263,7 +273,8 @@ void JsonCB::handlePriorityUpdate()
|
|||||||
LEDcolor.insert("RGB", RGBValue);
|
LEDcolor.insert("RGB", RGBValue);
|
||||||
|
|
||||||
uint16_t Hue;
|
uint16_t Hue;
|
||||||
float Saturation, Luminace;
|
float Saturation;
|
||||||
|
float Luminace;
|
||||||
|
|
||||||
// add HSL Value to Array
|
// add HSL Value to Array
|
||||||
QJsonArray HSLValue;
|
QJsonArray HSLValue;
|
||||||
|
@ -55,11 +55,7 @@ BoblightClientConnection::BoblightClientConnection(Hyperion* hyperion, QTcpSocke
|
|||||||
|
|
||||||
BoblightClientConnection::~BoblightClientConnection()
|
BoblightClientConnection::~BoblightClientConnection()
|
||||||
{
|
{
|
||||||
// clear the current channel
|
_socket->deleteLater();
|
||||||
if (_priority != 0 && _priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
|
|
||||||
_hyperion->clear(_priority);
|
|
||||||
|
|
||||||
delete _socket;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BoblightClientConnection::readData()
|
void BoblightClientConnection::readData()
|
||||||
@ -117,9 +113,10 @@ QString BoblightClientConnection::readMessage(const char* data, const size_t siz
|
|||||||
|
|
||||||
void BoblightClientConnection::socketClosed()
|
void BoblightClientConnection::socketClosed()
|
||||||
{
|
{
|
||||||
// clear the current channel
|
|
||||||
if (_priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
|
if (_priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
|
||||||
|
{
|
||||||
_hyperion->clear(_priority);
|
_hyperion->clear(_priority);
|
||||||
|
}
|
||||||
|
|
||||||
emit connectionClosed(this);
|
emit connectionClosed(this);
|
||||||
}
|
}
|
||||||
@ -205,40 +202,58 @@ void BoblightClientConnection::handleMessage(const QString& message)
|
|||||||
{
|
{
|
||||||
bool rc;
|
bool rc;
|
||||||
const int prio = static_cast<int>(parseUInt(messageParts[2], &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)
|
int currentPriority = _hyperion->getCurrentPriority();
|
||||||
_hyperion->clear(_priority);
|
|
||||||
|
|
||||||
if (prio < BOBLIGHT_MIN_PRIORITY || prio > BOBLIGHT_MAX_PRIORITY)
|
if (prio == currentPriority)
|
||||||
{
|
{
|
||||||
_priority = BOBLIGHT_DEFAULT_PRIORITY;
|
Error(_log, "The priority %i is already in use onther component of type [%s]", prio, componentToString(_hyperion->getPriorityInfo(currentPriority).componentId));
|
||||||
while (_hyperion->getActivePriorities().contains(_priority))
|
_socket->close();
|
||||||
{
|
|
||||||
_priority += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// warn against invalid priority
|
|
||||||
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()));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// register new priority
|
if (prio < BOBLIGHT_MIN_PRIORITY || prio > BOBLIGHT_MAX_PRIORITY)
|
||||||
_hyperion->registerInput(prio, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_socket->peerAddress().toString()));
|
{
|
||||||
_priority = prio;
|
_priority = BOBLIGHT_DEFAULT_PRIORITY;
|
||||||
}
|
while (_hyperion->getActivePriorities().contains(_priority))
|
||||||
|
{
|
||||||
|
_priority += 1;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
// warn against invalid priority
|
||||||
|
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(_clientAddress));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// register new priority
|
||||||
|
_hyperion->registerInput(prio, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_clientAddress));
|
||||||
|
_priority = prio;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (messageParts[0] == "sync")
|
else if (messageParts[0] == "sync")
|
||||||
{
|
{
|
||||||
if (_priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
|
if (_priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
|
||||||
_hyperion->setInput(_priority, _ledColors); // send current color values to hyperion
|
{
|
||||||
|
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;
|
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
|
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()
|
void BoblightClientConnection::sendLightMessage()
|
||||||
{
|
{
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
|
@ -36,6 +36,13 @@ public:
|
|||||||
///
|
///
|
||||||
~BoblightClientConnection() override;
|
~BoblightClientConnection() override;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the Boblight client's IP-address
|
||||||
|
///
|
||||||
|
/// @returns IP-address as QString
|
||||||
|
///
|
||||||
|
QString getClientAddress() { return _clientAddress; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
///
|
///
|
||||||
/// Signal which is emitted when the connection is being closed
|
/// Signal which is emitted when the connection is being closed
|
||||||
@ -67,7 +74,7 @@ private:
|
|||||||
///
|
///
|
||||||
/// @param message The boblight message to send
|
/// @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
|
/// Send a lights message the to connected client
|
||||||
|
@ -22,9 +22,12 @@ BoblightServer::BoblightServer(Hyperion* hyperion,const QJsonDocument& config)
|
|||||||
, _server(new QTcpServer(this))
|
, _server(new QTcpServer(this))
|
||||||
, _openConnections()
|
, _openConnections()
|
||||||
, _priority(0)
|
, _priority(0)
|
||||||
, _log(Logger::getInstance("BOBLIGHT"))
|
, _log(nullptr)
|
||||||
, _port(0)
|
, _port(0)
|
||||||
{
|
{
|
||||||
|
QString subComponent = _hyperion->property("instance").toString();
|
||||||
|
_log= Logger::getInstance("BOBLIGHT", subComponent);
|
||||||
|
|
||||||
Debug(_log, "Instance created");
|
Debug(_log, "Instance created");
|
||||||
|
|
||||||
// listen for component change
|
// listen for component change
|
||||||
@ -49,7 +52,7 @@ void BoblightServer::start()
|
|||||||
if (NetUtils::portAvailable(_port, _log))
|
if (NetUtils::portAvailable(_port, _log))
|
||||||
_server->listen(QHostAddress::Any, _port);
|
_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());
|
_hyperion->setNewComponentState(COMP_BOBLIGHTSERVER, _server->isListening());
|
||||||
}
|
}
|
||||||
@ -92,11 +95,9 @@ uint16_t BoblightServer::getPort() const
|
|||||||
void BoblightServer::newConnection()
|
void BoblightServer::newConnection()
|
||||||
{
|
{
|
||||||
QTcpSocket * socket = _server->nextPendingConnection();
|
QTcpSocket * socket = _server->nextPendingConnection();
|
||||||
|
|
||||||
if (socket != nullptr)
|
if (socket != nullptr)
|
||||||
{
|
{
|
||||||
Info(_log, "new connection");
|
Info(_log, "New connection from %s ", QSTRING_CSTR(QString("Boblight@%1").arg(socket->peerAddress().toString())));
|
||||||
_hyperion->registerInput(_priority, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(socket->peerAddress().toString()));
|
|
||||||
BoblightClientConnection * connection = new BoblightClientConnection(_hyperion, socket, _priority);
|
BoblightClientConnection * connection = new BoblightClientConnection(_hyperion, socket, _priority);
|
||||||
_openConnections.insert(connection);
|
_openConnections.insert(connection);
|
||||||
|
|
||||||
@ -107,7 +108,7 @@ void BoblightServer::newConnection()
|
|||||||
|
|
||||||
void BoblightServer::closedConnection(BoblightClientConnection *connection)
|
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);
|
_openConnections.remove(connection);
|
||||||
|
|
||||||
// schedule to delete the connection object
|
// schedule to delete the connection object
|
||||||
|
@ -219,7 +219,7 @@ void EffectEngine::effectFinished()
|
|||||||
_hyperion->clear(effect->getPriority());
|
_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)
|
for (auto effectIt = _activeEffects.begin(); effectIt != _activeEffects.end(); ++effectIt)
|
||||||
{
|
{
|
||||||
if (*effectIt == effect)
|
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();
|
const QJsonObject obj = _hyperion->getSetting(settings::NETFORWARD).object();
|
||||||
if (priority != 0 && _forwarder_enabled && obj["enable"].toBool())
|
if (priority != 0 && _forwarder_enabled && obj["enable"].toBool())
|
||||||
|
@ -66,9 +66,9 @@ bool QtGrabber::open()
|
|||||||
bool QtGrabber::setupDisplay()
|
bool QtGrabber::setupDisplay()
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if ( ! open() )
|
if (!open())
|
||||||
{
|
{
|
||||||
if ( _isWayland )
|
if (_isWayland)
|
||||||
{
|
{
|
||||||
Error(_log, "Grabber does not work under Wayland!");
|
Error(_log, "Grabber does not work under Wayland!");
|
||||||
}
|
}
|
||||||
@ -80,45 +80,46 @@ bool QtGrabber::setupDisplay()
|
|||||||
_numberOfSDisplays = 0;
|
_numberOfSDisplays = 0;
|
||||||
|
|
||||||
QScreen* primary = QGuiApplication::primaryScreen();
|
QScreen* primary = QGuiApplication::primaryScreen();
|
||||||
QList<QScreen *> screens = QGuiApplication::screens();
|
QList<QScreen*> screens = QGuiApplication::screens();
|
||||||
// inject main screen at 0, if not nullptr
|
// inject main screen at 0, if not nullptr
|
||||||
if(primary != nullptr)
|
if (primary != nullptr)
|
||||||
{
|
{
|
||||||
screens.prepend(primary);
|
screens.prepend(primary);
|
||||||
// remove last main screen if twice in list
|
// remove last main screen if twice in list
|
||||||
if(screens.lastIndexOf(primary) > 0)
|
if (screens.lastIndexOf(primary) > 0)
|
||||||
{
|
{
|
||||||
screens.removeAt(screens.lastIndexOf(primary));
|
screens.removeAt(screens.lastIndexOf(primary));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(screens.isEmpty())
|
if (screens.isEmpty())
|
||||||
{
|
{
|
||||||
Error(_log, "No displays found to capture from!");
|
Error(_log, "No displays found to capture from!");
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_numberOfSDisplays = screens.size();
|
_numberOfSDisplays = screens.size();
|
||||||
|
|
||||||
Info(_log,"Available Displays:");
|
Info(_log, "Available Displays:");
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for(auto * screen : qAsConst(screens))
|
for (auto* screen : qAsConst(screens))
|
||||||
{
|
{
|
||||||
const QRect geo = screen->geometry();
|
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;
|
++index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (screens.at(0)->size() != screens.at(0)->virtualSize())
|
if (screens.at(0)->size() != screens.at(0)->virtualSize())
|
||||||
{
|
{
|
||||||
const QRect vgeo = screens.at(0)->virtualGeometry();
|
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;
|
_isVirtual = false;
|
||||||
// be sure the index is available
|
// 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))
|
if ((screens.at(0)->size() != screens.at(0)->virtualSize()) && (_display == _numberOfSDisplays))
|
||||||
@ -145,17 +146,17 @@ bool QtGrabber::setupDisplay()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Info(_log,"Initialized display %d", _display);
|
Info(_log, "Initialized display %d", _display);
|
||||||
}
|
}
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
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);
|
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
|
QPixmap QtGrabber::grabWindow(quintptr window, int xIn, int yIn, int width, int height) const
|
||||||
{
|
{
|
||||||
QSize windowSize;
|
QSize windowSize;
|
||||||
int x = xIn;
|
|
||||||
int y = yIn;
|
|
||||||
HWND hwnd = reinterpret_cast<HWND>(window);
|
HWND hwnd = reinterpret_cast<HWND>(window);
|
||||||
if (hwnd)
|
if (hwnd)
|
||||||
{
|
{
|
||||||
@ -179,15 +178,13 @@ QPixmap QtGrabber::grabWindow(quintptr window, int xIn, int yIn, int width, int
|
|||||||
hwnd = GetDesktopWindow();
|
hwnd = GetDesktopWindow();
|
||||||
const QRect screenGeometry = _screen->geometry();
|
const QRect screenGeometry = _screen->geometry();
|
||||||
windowSize = screenGeometry.size();
|
windowSize = screenGeometry.size();
|
||||||
x += screenGeometry.x();
|
|
||||||
y += screenGeometry.y();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (width < 0)
|
if (width < 0)
|
||||||
width = windowSize.width() - x;
|
width = windowSize.width() - xIn;
|
||||||
|
|
||||||
if (height < 0)
|
if (height < 0)
|
||||||
height = windowSize.height() - y;
|
height = windowSize.height() - yIn;
|
||||||
|
|
||||||
// Create and setup bitmap
|
// Create and setup bitmap
|
||||||
HDC display_dc = GetDC(nullptr);
|
HDC display_dc = GetDC(nullptr);
|
||||||
@ -197,7 +194,7 @@ QPixmap QtGrabber::grabWindow(quintptr window, int xIn, int yIn, int width, int
|
|||||||
|
|
||||||
// copy data
|
// copy data
|
||||||
HDC window_dc = GetDC(hwnd);
|
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
|
// clean up all but bitmap
|
||||||
ReleaseDC(hwnd, window_dc);
|
ReleaseDC(hwnd, window_dc);
|
||||||
@ -211,12 +208,12 @@ QPixmap QtGrabber::grabWindow(quintptr window, int xIn, int yIn, int width, int
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
int QtGrabber::grabFrame(Image<ColorRgb>& image)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
if (_isEnabled && !_isDeviceInError)
|
if (_isEnabled && !_isDeviceInError)
|
||||||
{
|
{
|
||||||
if(_screen == nullptr)
|
if (_screen == nullptr)
|
||||||
{
|
{
|
||||||
// reinit, this will disable capture on failure
|
// reinit, this will disable capture on failure
|
||||||
bool result = setupDisplay();
|
bool result = setupDisplay();
|
||||||
@ -229,14 +226,14 @@ int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
|||||||
QPixmap originalPixmap = grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max);
|
QPixmap originalPixmap = grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max);
|
||||||
#else
|
#else
|
||||||
QPixmap originalPixmap = _screen->grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max);
|
QPixmap originalPixmap = _screen->grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max);
|
||||||
#endif
|
#endif
|
||||||
if (originalPixmap.isNull())
|
if (originalPixmap.isNull())
|
||||||
{
|
{
|
||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
else
|
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));
|
image.resize(static_cast<uint>(_calculatedWidth), static_cast<uint>(_calculatedHeight));
|
||||||
|
|
||||||
for (int y = 0; y < imageFrame.height(); y++)
|
for (int y = 0; y < imageFrame.height(); y++)
|
||||||
@ -251,7 +248,7 @@ int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
|||||||
|
|
||||||
int QtGrabber::updateScreenDimensions(bool force)
|
int QtGrabber::updateScreenDimensions(bool force)
|
||||||
{
|
{
|
||||||
if(_screen == nullptr)
|
if (_screen == nullptr)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -273,53 +270,65 @@ int QtGrabber::updateScreenDimensions(bool force)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Info(_log, "Update of screen resolution: [%dx%d] to [%dx%d]", _width, _height, geo.width(), geo.height());
|
Info(_log, "Update of screen resolution: [%dx%d] to [%dx%d]", _width, _height, geo.width(), geo.height());
|
||||||
_width = geo.width();
|
_width = geo.width();
|
||||||
_height = geo.height();
|
_height = geo.height();
|
||||||
|
|
||||||
int width=0;
|
int width = 0;
|
||||||
int height=0;
|
int height = 0;
|
||||||
|
|
||||||
// Image scaling is performed by Qt
|
// Image scaling is performed by Qt
|
||||||
width = (_width > (_cropLeft + _cropRight))
|
width = (_width > (_cropLeft + _cropRight))
|
||||||
? ((_width - _cropLeft - _cropRight) / _pixelDecimation)
|
? ((_width - _cropLeft - _cropRight) / _pixelDecimation)
|
||||||
: (_width / _pixelDecimation);
|
: (_width / _pixelDecimation);
|
||||||
|
|
||||||
height = (_height > (_cropTop + _cropBottom))
|
height = (_height > (_cropTop + _cropBottom))
|
||||||
? ((_height - _cropTop - _cropBottom) / _pixelDecimation)
|
? ((_height - _cropTop - _cropBottom) / _pixelDecimation)
|
||||||
: (_height / _pixelDecimation);
|
: (_height / _pixelDecimation);
|
||||||
|
|
||||||
|
|
||||||
// calculate final image dimensions and adjust top/left cropping in 3D modes
|
// 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)
|
switch (_videoMode)
|
||||||
{
|
{
|
||||||
case VideoMode::VIDEO_3DSBS:
|
case VideoMode::VIDEO_3DSBS:
|
||||||
_calculatedWidth = width /2;
|
_calculatedWidth = width / 2;
|
||||||
_calculatedHeight = height;
|
_calculatedHeight = height;
|
||||||
_src_x = _cropLeft / 2;
|
_src_x = _src_x + (_cropLeft / 2);
|
||||||
_src_y = _cropTop;
|
_src_y = _src_y + _cropTop;
|
||||||
_src_x_max = (_width / 2) - _cropRight - _cropLeft;
|
_src_x_max = (_width / 2) - _cropRight - _cropLeft;
|
||||||
_src_y_max = _height - _cropBottom - _cropTop;
|
_src_y_max = _height - _cropBottom - _cropTop;
|
||||||
break;
|
break;
|
||||||
case VideoMode::VIDEO_3DTAB:
|
case VideoMode::VIDEO_3DTAB:
|
||||||
_calculatedWidth = width;
|
_calculatedWidth = width;
|
||||||
_calculatedHeight = height / 2;
|
_calculatedHeight = height / 2;
|
||||||
_src_x = _cropLeft;
|
_src_x = _src_x + _cropLeft;
|
||||||
_src_y = _cropTop / 2;
|
_src_y = _src_y + (_cropTop / 2);
|
||||||
_src_x_max = _width - _cropRight - _cropLeft;
|
_src_x_max = _width - _cropRight - _cropLeft;
|
||||||
_src_y_max = (_height / 2) - _cropBottom - _cropTop;
|
_src_y_max = (_height / 2) - _cropBottom - _cropTop;
|
||||||
break;
|
break;
|
||||||
case VideoMode::VIDEO_2D:
|
case VideoMode::VIDEO_2D:
|
||||||
default:
|
default:
|
||||||
_calculatedWidth = width;
|
_calculatedWidth = width;
|
||||||
_calculatedHeight = height;
|
_calculatedHeight = height;
|
||||||
_src_x = _cropLeft;
|
_src_x = _src_x + _cropLeft;
|
||||||
_src_y = _cropTop;
|
_src_y = _src_y + _cropTop;
|
||||||
_src_x_max = _width - _cropRight - _cropLeft;
|
_src_x_max = _width - _cropRight - _cropLeft;
|
||||||
_src_y_max = _height - _cropBottom - _cropTop;
|
_src_y_max = _height - _cropBottom - _cropTop;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Info(_log, "Update output image resolution to [%dx%d]", _calculatedWidth, _calculatedHeight);
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,10 +340,10 @@ void QtGrabber::setVideoMode(VideoMode mode)
|
|||||||
|
|
||||||
bool QtGrabber::setPixelDecimation(int pixelDecimation)
|
bool QtGrabber::setPixelDecimation(int pixelDecimation)
|
||||||
{
|
{
|
||||||
bool rc (true);
|
bool rc(true);
|
||||||
if(Grabber::setPixelDecimation(pixelDecimation))
|
if (Grabber::setPixelDecimation(pixelDecimation))
|
||||||
{
|
{
|
||||||
if ( updateScreenDimensions(true) < 0)
|
if (updateScreenDimensions(true) < 0)
|
||||||
{
|
{
|
||||||
rc = false;
|
rc = false;
|
||||||
}
|
}
|
||||||
@ -350,14 +359,20 @@ void QtGrabber::setCropping(int cropLeft, int cropRight, int cropTop, int cropBo
|
|||||||
|
|
||||||
bool QtGrabber::setDisplayIndex(int index)
|
bool QtGrabber::setDisplayIndex(int index)
|
||||||
{
|
{
|
||||||
bool rc (true);
|
bool rc(true);
|
||||||
if (_display != index)
|
if (_display != index || _isVirtual)
|
||||||
{
|
{
|
||||||
|
_isVirtual = false;
|
||||||
if (index <= _numberOfSDisplays)
|
if (index <= _numberOfSDisplays)
|
||||||
{
|
{
|
||||||
_display = index;
|
_display = index;
|
||||||
|
if (index == _numberOfSDisplays)
|
||||||
|
{
|
||||||
|
_isVirtual = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
_display = 0;
|
_display = 0;
|
||||||
}
|
}
|
||||||
rc = setupDisplay();
|
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());
|
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
QJsonObject inputsDiscovered;
|
QJsonObject inputsDiscovered;
|
||||||
if ( open() )
|
if (open())
|
||||||
{
|
{
|
||||||
QList<QScreen*> screens = QGuiApplication::screens();
|
QList<QScreen*> screens = QGuiApplication::screens();
|
||||||
if (!screens.isEmpty())
|
if (!screens.isEmpty())
|
||||||
@ -390,7 +405,7 @@ QJsonObject QtGrabber::discover(const QJsonObject& params)
|
|||||||
int pos = name.lastIndexOf('\\');
|
int pos = name.lastIndexOf('\\');
|
||||||
if (pos != -1)
|
if (pos != -1)
|
||||||
{
|
{
|
||||||
name = name.right(name.length()-pos-1);
|
name = name.right(name.length() - pos - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
in["name"] = name;
|
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());
|
DebugIf(verbose, _log, "device: [%s]", QString(QJsonDocument(inputsDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
return inputsDiscovered;
|
return inputsDiscovered;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -193,7 +193,10 @@ void Hyperion::stop()
|
|||||||
|
|
||||||
void Hyperion::freeObjects()
|
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);
|
clear(-1,true);
|
||||||
|
|
||||||
// delete components on exit of hyperion core
|
// delete components on exit of hyperion core
|
||||||
@ -462,11 +465,6 @@ void Hyperion::setColor(int priority, const std::vector<ColorRgb> &ledColors, in
|
|||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
|
|
||||||
if (getPriorityInfo(priority).componentId != hyperion::COMP_COLOR)
|
|
||||||
{
|
|
||||||
clear(priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
// register color
|
// register color
|
||||||
registerInput(priority, hyperion::COMP_COLOR, origin);
|
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));
|
_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();
|
{ int previousPriority = _muxer->getPreviousPriority();
|
||||||
|
|
||||||
Debug(_log,"priority[%d], previousPriority[%d]", priority, previousPriority);
|
|
||||||
if ( priority == PriorityMuxer::LOWEST_PRIORITY)
|
if ( priority == PriorityMuxer::LOWEST_PRIORITY)
|
||||||
{
|
{
|
||||||
Debug(_log,"No source left -> Pause output processing and switch LED-Device off");
|
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::MANUAL_SELECTED_PRIORITY = 256;
|
||||||
const int PriorityMuxer::LOWEST_PRIORITY = std::numeric_limits<uint8_t>::max();
|
const int PriorityMuxer::LOWEST_PRIORITY = std::numeric_limits<uint8_t>::max();
|
||||||
const int PriorityMuxer::TIMEOUT_NOT_ACTIVE_PRIO = -100;
|
const int PriorityMuxer::TIMEOUT_NOT_ACTIVE_PRIO = -100;
|
||||||
|
const int PriorityMuxer::REMOVE_CLEARED_PRIO = -101;
|
||||||
const int PriorityMuxer::ENDLESS = -1;
|
const int PriorityMuxer::ENDLESS = -1;
|
||||||
|
|
||||||
PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
||||||
@ -26,8 +27,6 @@ PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
|||||||
, _previousPriority(_currentPriority)
|
, _previousPriority(_currentPriority)
|
||||||
, _manualSelectedPriority(MANUAL_SELECTED_PRIORITY)
|
, _manualSelectedPriority(MANUAL_SELECTED_PRIORITY)
|
||||||
, _prevVisComp (hyperion::Components::COMP_COLOR)
|
, _prevVisComp (hyperion::Components::COMP_COLOR)
|
||||||
, _activeInputs()
|
|
||||||
, _lowestPriorityInfo()
|
|
||||||
, _sourceAutoSelectEnabled(true)
|
, _sourceAutoSelectEnabled(true)
|
||||||
, _updateTimer(new QTimer(this))
|
, _updateTimer(new QTimer(this))
|
||||||
, _timer(new QTimer(this))
|
, _timer(new QTimer(this))
|
||||||
@ -38,8 +37,10 @@ PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
|||||||
|
|
||||||
// init lowest priority info
|
// init lowest priority info
|
||||||
_lowestPriorityInfo.priority = PriorityMuxer::LOWEST_PRIORITY;
|
_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.componentId = hyperion::COMP_COLOR;
|
||||||
_lowestPriorityInfo.origin = "System";
|
_lowestPriorityInfo.origin = "System";
|
||||||
_lowestPriorityInfo.owner = "";
|
_lowestPriorityInfo.owner = "";
|
||||||
@ -50,12 +51,10 @@ PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
|||||||
connect(_timer, &QTimer::timeout, this, &PriorityMuxer::timeTrigger);
|
connect(_timer, &QTimer::timeout, this, &PriorityMuxer::timeTrigger);
|
||||||
_timer->setSingleShot(true);
|
_timer->setSingleShot(true);
|
||||||
_blockTimer->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);
|
connect(this, &PriorityMuxer::signalTimeTrigger, this, &PriorityMuxer::timeTrigger);
|
||||||
|
|
||||||
// start muxer timer
|
// start muxer timer
|
||||||
connect(_updateTimer, &QTimer::timeout, this, &PriorityMuxer::setCurrentTime);
|
connect(_updateTimer, &QTimer::timeout, this, &PriorityMuxer::updatePriorities);
|
||||||
_updateTimer->setInterval(250);
|
_updateTimer->setInterval(250);
|
||||||
_updateTimer->start();
|
_updateTimer->start();
|
||||||
}
|
}
|
||||||
@ -85,7 +84,9 @@ bool PriorityMuxer::setSourceAutoSelectEnabled(bool enable, bool update)
|
|||||||
|
|
||||||
// update _currentPriority if called from external
|
// update _currentPriority if called from external
|
||||||
if(update)
|
if(update)
|
||||||
setCurrentTime();
|
{
|
||||||
|
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -128,10 +129,10 @@ bool PriorityMuxer::hasPriority(int priority) const
|
|||||||
|
|
||||||
PriorityMuxer::InputInfo PriorityMuxer::getInputInfo(int priority) const
|
PriorityMuxer::InputInfo PriorityMuxer::getInputInfo(int priority) const
|
||||||
{
|
{
|
||||||
auto elemIt = _activeInputs.find(priority);
|
auto elemIt = _activeInputs.constFind(priority);
|
||||||
if (elemIt == _activeInputs.end())
|
if (elemIt == _activeInputs.end())
|
||||||
{
|
{
|
||||||
elemIt = _activeInputs.find(PriorityMuxer::LOWEST_PRIORITY);
|
elemIt = _activeInputs.constFind(PriorityMuxer::LOWEST_PRIORITY);
|
||||||
if (elemIt == _activeInputs.end())
|
if (elemIt == _activeInputs.end())
|
||||||
{
|
{
|
||||||
// fallback
|
// fallback
|
||||||
@ -150,11 +151,18 @@ void PriorityMuxer::registerInput(int priority, hyperion::Components component,
|
|||||||
{
|
{
|
||||||
// detect new registers
|
// detect new registers
|
||||||
bool newInput = false;
|
bool newInput = false;
|
||||||
bool reusedInput = false;
|
|
||||||
if (!_activeInputs.contains(priority))
|
if (!_activeInputs.contains(priority))
|
||||||
|
{
|
||||||
newInput = true;
|
newInput = true;
|
||||||
|
}
|
||||||
else if(_prevVisComp == component || _activeInputs[priority].componentId == component)
|
else if(_prevVisComp == component || _activeInputs[priority].componentId == component)
|
||||||
reusedInput = true;
|
{
|
||||||
|
if (_activeInputs[priority].owner != owner)
|
||||||
|
{
|
||||||
|
newInput = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InputInfo& input = _activeInputs[priority];
|
InputInfo& input = _activeInputs[priority];
|
||||||
input.priority = priority;
|
input.priority = priority;
|
||||||
@ -166,18 +174,11 @@ void PriorityMuxer::registerInput(int priority, hyperion::Components component,
|
|||||||
|
|
||||||
if (newInput)
|
if (newInput)
|
||||||
{
|
{
|
||||||
Debug(_log,"Register new input '%s/%s' with priority %d as inactive", QSTRING_CSTR(origin), hyperion::componentToIdString(component), priority);
|
Debug(_log,"Register new input '%s/%s' (%s) with priority %d as inactive", QSTRING_CSTR(origin), hyperion::componentToIdString(component), QSTRING_CSTR(owner), priority);
|
||||||
// emit 'prioritiesChanged' only if _sourceAutoSelectEnabled is false
|
|
||||||
if (!_sourceAutoSelectEnabled)
|
|
||||||
{
|
|
||||||
emit prioritiesChanged();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (reusedInput)
|
|
||||||
{
|
{
|
||||||
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
|
// emit active change
|
||||||
if(activeChange)
|
if(activeChange)
|
||||||
{
|
{
|
||||||
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
|
if (_currentPriority <= priority || !_sourceAutoSelectEnabled)
|
||||||
if (_currentPriority < priority)
|
|
||||||
{
|
{
|
||||||
emit prioritiesChanged();
|
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
|
||||||
|
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||||
}
|
}
|
||||||
setCurrentTime();
|
updatePriorities();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -272,12 +273,12 @@ bool PriorityMuxer::setInputImage(int priority, const Image<ColorRgb>& image, in
|
|||||||
// emit active change
|
// emit active change
|
||||||
if(activeChange)
|
if(activeChange)
|
||||||
{
|
{
|
||||||
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
|
if (_currentPriority <= priority || !_sourceAutoSelectEnabled)
|
||||||
if (_currentPriority < priority)
|
|
||||||
{
|
{
|
||||||
emit prioritiesChanged();
|
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
|
||||||
|
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||||
}
|
}
|
||||||
setCurrentTime();
|
updatePriorities();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -291,14 +292,9 @@ bool PriorityMuxer::setInputInactive(int priority)
|
|||||||
|
|
||||||
bool PriorityMuxer::clearInput(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);
|
_activeInputs[priority].timeoutTime_ms = REMOVE_CLEARED_PRIO;
|
||||||
// on clear success update _currentPriority
|
|
||||||
setCurrentTime();
|
|
||||||
// emit 'prioritiesChanged' only if _sourceAutoSelectEnabled is false
|
|
||||||
if ((!_sourceAutoSelectEnabled && (_currentPriority < priority)) || _currentPriority == BG_PRIORITY)
|
|
||||||
emit prioritiesChanged();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -312,6 +308,7 @@ void PriorityMuxer::clearAll(bool forceClearAll)
|
|||||||
_activeInputs.clear();
|
_activeInputs.clear();
|
||||||
_currentPriority = PriorityMuxer::LOWEST_PRIORITY;
|
_currentPriority = PriorityMuxer::LOWEST_PRIORITY;
|
||||||
_activeInputs[_currentPriority] = _lowestPriorityInfo;
|
_activeInputs[_currentPriority] = _lowestPriorityInfo;
|
||||||
|
updatePriorities();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -326,35 +323,61 @@ void PriorityMuxer::clearAll(bool forceClearAll)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PriorityMuxer::setCurrentTime()
|
void PriorityMuxer::updatePriorities()
|
||||||
{
|
{
|
||||||
const int64_t now = QDateTime::currentMSecsSinceEpoch();
|
const int64_t now = QDateTime::currentMSecsSinceEpoch();
|
||||||
int newPriority;
|
int newPriority;
|
||||||
|
bool priorityChanged {false};
|
||||||
|
|
||||||
_activeInputs.contains(0) ? newPriority = 0 : newPriority = PriorityMuxer::LOWEST_PRIORITY;
|
_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()) {
|
||||||
if (infoIt->timeoutTime_ms > 0 && infoIt->timeoutTime_ms <= now)
|
i.next();
|
||||||
|
|
||||||
|
if ( i.value().timeoutTime_ms == REMOVE_CLEARED_PRIO )
|
||||||
{
|
{
|
||||||
int tPrio = infoIt->priority;
|
int tPrio = i.value().priority;
|
||||||
infoIt = _activeInputs.erase(infoIt);
|
i.remove();
|
||||||
Debug(_log,"Timeout clear for priority %d",tPrio);
|
|
||||||
emit prioritiesChanged();
|
Debug(_log,"Removed source priority %d", tPrio);
|
||||||
|
priorityChanged = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// timeoutTime of TIMEOUT_NOT_ACTIVE_PRIO is awaiting data (inactive); skip
|
if (i.value().timeoutTime_ms > 0 && i.value().timeoutTime_ms <= now)
|
||||||
if(infoIt->timeoutTime_ms > TIMEOUT_NOT_ACTIVE_PRIO)
|
|
||||||
newPriority = qMin(newPriority, infoIt->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))
|
|
||||||
{
|
{
|
||||||
emit signalTimeTrigger(); // as signal to prevent Threading issues
|
//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);
|
||||||
|
priorityChanged = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// timeoutTime of TIMEOUT_NOT_ACTIVE_PRIO is awaiting data (inactive); skip
|
||||||
|
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 (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
|
// evaluate, if manual selected priority is still available
|
||||||
if(!_sourceAutoSelectEnabled)
|
if(!_sourceAutoSelectEnabled)
|
||||||
{
|
{
|
||||||
@ -371,7 +394,7 @@ void PriorityMuxer::setCurrentTime()
|
|||||||
}
|
}
|
||||||
// apply & emit on change (after apply!)
|
// apply & emit on change (after apply!)
|
||||||
hyperion::Components comp = getComponentOfPriority(newPriority);
|
hyperion::Components comp = getComponentOfPriority(newPriority);
|
||||||
if (_currentPriority != newPriority || comp != _prevVisComp)
|
if (_currentPriority != newPriority || comp != _prevVisComp )
|
||||||
{
|
{
|
||||||
_previousPriority = _currentPriority;
|
_previousPriority = _currentPriority;
|
||||||
_currentPriority = newPriority;
|
_currentPriority = newPriority;
|
||||||
@ -383,7 +406,12 @@ void PriorityMuxer::setCurrentTime()
|
|||||||
_prevVisComp = comp;
|
_prevVisComp = comp;
|
||||||
emit visibleComponentChanged(comp);
|
emit visibleComponentChanged(comp);
|
||||||
}
|
}
|
||||||
emit prioritiesChanged();
|
priorityChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priorityChanged)
|
||||||
|
{
|
||||||
|
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,7 +423,7 @@ void PriorityMuxer::timeTrigger()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
emit timeRunner();
|
|
||||||
_blockTimer->start(1000);
|
_blockTimer->start(1000);
|
||||||
|
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
"type" : "integer",
|
"type" : "integer",
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"title" : "edt_conf_general_port_title",
|
"title" : "edt_conf_general_port_title",
|
||||||
|
"default" : 19333,
|
||||||
"minimum" : 1024,
|
"minimum" : 1024,
|
||||||
"maximum" : 65535,
|
"maximum" : 65535,
|
||||||
"propertyOrder" : 2
|
"propertyOrder" : 2
|
||||||
|
@ -137,6 +137,10 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [ "snake", "parallel" ]
|
"enum": [ "snake", "parallel" ]
|
||||||
},
|
},
|
||||||
|
"direction": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [ "horizontal", "vertical" ]
|
||||||
|
},
|
||||||
"start": {
|
"start": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ]
|
"enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ]
|
||||||
|
@ -357,8 +357,10 @@ QJsonObject LedDeviceWled::getProperties(const QJsonObject& params)
|
|||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject propertiesDetails = response.getBody().object();
|
QJsonObject propertiesDetails = response.getBody().object();
|
||||||
propertiesDetails.insert("maxLedCount", UDP_MAX_LED_NUM);
|
if (!propertiesDetails.isEmpty())
|
||||||
|
{
|
||||||
|
propertiesDetails.insert("maxLedCount", UDP_MAX_LED_NUM);
|
||||||
|
}
|
||||||
properties.insert("properties", propertiesDetails);
|
properties.insert("properties", propertiesDetails);
|
||||||
|
|
||||||
DebugIf(verbose, _log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
DebugIf(verbose, _log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||||
|
@ -98,10 +98,14 @@ void QtHttpClientWrapper::onClientDataReceived (void)
|
|||||||
|
|
||||||
if (pos > 0)
|
if (pos > 0)
|
||||||
{
|
{
|
||||||
QByteArray header = raw.left (pos).trimmed ();
|
QByteArray header = raw.left (pos).trimmed();
|
||||||
QByteArray value = raw.mid (pos +1).trimmed ();
|
QByteArray value = raw.mid (pos +1).trimmed();
|
||||||
m_currentRequest->addHeader (header, value);
|
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;
|
bool ok = false;
|
||||||
const int len = value.toInt (&ok, 10);
|
const int len = value.toInt (&ok, 10);
|
||||||
@ -153,7 +157,7 @@ void QtHttpClientWrapper::onClientDataReceived (void)
|
|||||||
case RequestParsed: // a valid request has ben fully parsed
|
case RequestParsed: // a valid request has ben fully parsed
|
||||||
{
|
{
|
||||||
// Catch websocket header "Upgrade"
|
// Catch websocket header "Upgrade"
|
||||||
if(m_currentRequest->getHeader(QtHttpHeader::Upgrade).toLower() == "websocket")
|
if(m_currentRequest->getHeader(QtHttpHeader::Upgrade) == "websocket")
|
||||||
{
|
{
|
||||||
if(m_websocketClient == Q_NULLPTR)
|
if(m_websocketClient == Q_NULLPTR)
|
||||||
{
|
{
|
||||||
@ -327,7 +331,7 @@ QtHttpClientWrapper::ParsingStatus QtHttpClientWrapper::sendReplyToClient (QtHtt
|
|||||||
{
|
{
|
||||||
static const QByteArray & CLOSE = QByteArrayLiteral ("close");
|
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
|
// must close connection after this request
|
||||||
m_sockClient->close ();
|
m_sockClient->close ();
|
||||||
|
@ -25,7 +25,7 @@ void QtHttpRequest::setClientInfo (const QHostAddress & server, const QHostAddre
|
|||||||
|
|
||||||
void QtHttpRequest::addHeader (const QByteArray & header, const QByteArray & value)
|
void QtHttpRequest::addHeader (const QByteArray & header, const QByteArray & value)
|
||||||
{
|
{
|
||||||
QByteArray key = header.trimmed ();
|
QByteArray key = header.trimmed().toLower();
|
||||||
|
|
||||||
if (!key.isEmpty ())
|
if (!key.isEmpty ())
|
||||||
{
|
{
|
||||||
|
@ -38,7 +38,7 @@ public:
|
|||||||
|
|
||||||
QByteArray getHeader (const QByteArray & header) const
|
QByteArray getHeader (const QByteArray & header) const
|
||||||
{
|
{
|
||||||
return m_headersHash.value (header, QByteArray ());
|
return m_headersHash.value (header.toLower(), QByteArray ());
|
||||||
};
|
};
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -68,7 +68,7 @@ void JsonConnection::setColor(std::vector<QColor> colors, int priority, int dura
|
|||||||
parseReply(reply);
|
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());
|
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["command"] = QString("image");
|
||||||
command["priority"] = priority;
|
command["priority"] = priority;
|
||||||
command["origin"] = QString("hyperion-remote");
|
command["origin"] = QString("hyperion-remote");
|
||||||
|
if (!name.isEmpty())
|
||||||
|
command["name"] = name;
|
||||||
command["imagewidth"] = image.width();
|
command["imagewidth"] = image.width();
|
||||||
command["imageheight"] = image.height();
|
command["imageheight"] = image.height();
|
||||||
command["imagedata"] = QString(base64Image.data());
|
command["imagedata"] = QString(base64Image.data());
|
||||||
|
@ -41,13 +41,14 @@ public:
|
|||||||
void setColor(std::vector<QColor> color, int priority, int duration);
|
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 image The image
|
||||||
/// @param priority The priority
|
/// @param priority The priority
|
||||||
/// @param duration The duration in milliseconds
|
/// @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)
|
#if defined(ENABLE_EFFECTENGINE)
|
||||||
///
|
///
|
||||||
|
@ -252,7 +252,8 @@ int main(int argc, char * argv[])
|
|||||||
}
|
}
|
||||||
else if (parser.isSet(argImage))
|
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)
|
#if defined(ENABLE_EFFECTENGINE)
|
||||||
else if (parser.isSet(argEffect))
|
else if (parser.isSet(argEffect))
|
||||||
|
@ -103,23 +103,7 @@ QCoreApplication* createApplication(int &argc, char *argv[])
|
|||||||
#else
|
#else
|
||||||
if (!forceNoGui)
|
if (!forceNoGui)
|
||||||
{
|
{
|
||||||
// if x11, then test if xserver is available
|
isGuiApp = (getenv("DISPLAY") != NULL && (getenv("XDG_SESSION_TYPE") != NULL || getenv("WAYLAND_DISPLAY") != NULL));
|
||||||
#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
|
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
Debug(log,"QtVersion [%s]", QT_VERSION_STR);
|
||||||
|
|
||||||
if ( !readonlyMode )
|
if ( !readonlyMode )
|
||||||
@ -423,7 +407,7 @@ int main(int argc, char** argv)
|
|||||||
// run the application
|
// run the application
|
||||||
if (isGuiApp)
|
if (isGuiApp)
|
||||||
{
|
{
|
||||||
Info(log, "start systray");
|
Info(log, "Start Systray menu");
|
||||||
QApplication::setQuitOnLastWindowClosed(false);
|
QApplication::setQuitOnLastWindowClosed(false);
|
||||||
SysTray tray(hyperiond);
|
SysTray tray(hyperiond);
|
||||||
tray.hide();
|
tray.hide();
|
||||||
|
Loading…
Reference in New Issue
Block a user