Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a4d32aaac | ||
|
|
5c2357edd6 | ||
|
|
47ca57b9da | ||
|
|
f7e98cbd50 | ||
|
|
d1c059df7d | ||
|
|
92f4db9e73 | ||
|
|
11851bba1e | ||
|
|
3f7998934b | ||
|
|
4eea123fac | ||
|
|
3a447604c9 | ||
|
|
c6d23df938 | ||
|
|
32367c2ba2 | ||
|
|
9e80ae6150 | ||
|
|
ead6db5a48 | ||
|
|
4d277dc5c5 | ||
|
|
d0dfec4cde | ||
|
|
4db55e754c | ||
|
|
32b47e9a41 |
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
MaterialDeck.zip
|
||||
137
MaterialDeck.js
@@ -11,26 +11,26 @@ export var streamDeck;
|
||||
export var tokenControl;
|
||||
var move;
|
||||
export var macroControl;
|
||||
var combatTracker;
|
||||
var playlistControl;
|
||||
var soundboard;
|
||||
var otherControls;
|
||||
export var combatTracker;
|
||||
export var playlistControl;
|
||||
export var soundboard;
|
||||
export var otherControls;
|
||||
|
||||
export const moduleName = "MaterialDeck";
|
||||
export var selectedTokenId;
|
||||
|
||||
let ready = false;
|
||||
let activeSounds = [];
|
||||
|
||||
//CONFIG.debug.hooks = true;
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Global variables
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
var enableModule;
|
||||
export var enableModule;
|
||||
|
||||
//Websocket variables
|
||||
let ip = "localhost"; //Ip address of the websocket server
|
||||
let port = "3003"; //Port of the websocket server
|
||||
var ws; //Websocket variable
|
||||
let wsOpen = false; //Bool for checking if websocket has ever been opened => changes the warning message if there's no connection
|
||||
let wsInterval; //Interval timer to detect disconnections
|
||||
@@ -41,11 +41,20 @@ let WSconnected = false;
|
||||
*
|
||||
* @param {*} msg Message received
|
||||
*/
|
||||
async function analyzeWSmessage(msg,passthrough = false){
|
||||
async function analyzeWSmessage(msg){
|
||||
if (enableModule == false) return;
|
||||
const data = JSON.parse(msg);
|
||||
//console.log("Received",data);
|
||||
|
||||
if (data.type == "connected" && data.data == "SD"){
|
||||
console.log("streamdeck connected to server");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (data == undefined || data.payload == undefined) return;
|
||||
console.log(data);
|
||||
|
||||
const action = data.action;
|
||||
const event = data.event;
|
||||
const context = data.context;
|
||||
@@ -62,7 +71,7 @@ async function analyzeWSmessage(msg,passthrough = false){
|
||||
streamDeck.setContext(action,context,coordinates,settings);
|
||||
|
||||
if (action == 'token'){
|
||||
if (selectedTokenId != undefined)
|
||||
tokenControl.active = true;
|
||||
tokenControl.update(selectedTokenId);
|
||||
}
|
||||
else if (action == 'macro')
|
||||
@@ -92,17 +101,16 @@ async function analyzeWSmessage(msg,passthrough = false){
|
||||
combatTracker.keyPress(settings,context);
|
||||
else if (action == 'playlist')
|
||||
playlistControl.keyPress(settings,context);
|
||||
else if (action == 'soundboard'){
|
||||
else if (action == 'soundboard')
|
||||
soundboard.keyPressDown(settings);
|
||||
}
|
||||
else if (action == 'other')
|
||||
otherControls.keyPress(settings);
|
||||
}
|
||||
|
||||
else if (event == 'keyUp'){
|
||||
if (action == 'soundboard'){
|
||||
soundboard.keyPressUp(settings);
|
||||
}
|
||||
else if (action == 'other')
|
||||
otherControls.keyPress(settings);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -113,12 +121,11 @@ async function analyzeWSmessage(msg,passthrough = false){
|
||||
* If message is received, reset the interval, and send the message to analyzeWSmessage()
|
||||
*/
|
||||
function startWebsocket() {
|
||||
//ip = localhost;
|
||||
ws = new WebSocket('ws://'+ip+':'+port+'/1');
|
||||
const address = game.settings.get(moduleName,'address');
|
||||
ws = new WebSocket('ws://'+address+'/');
|
||||
|
||||
ws.onmessage = function(msg){
|
||||
//console.log(msg);
|
||||
|
||||
analyzeWSmessage(msg.data);
|
||||
clearInterval(wsInterval);
|
||||
wsInterval = setInterval(resetWS, 5000);
|
||||
@@ -126,12 +133,18 @@ function startWebsocket() {
|
||||
|
||||
ws.onopen = function() {
|
||||
WSconnected = true;
|
||||
ui.notifications.info("Material Deck Connected: "+ip+':'+port);
|
||||
ui.notifications.info("Material Deck "+game.i18n.localize("MaterialDeck.Notifications.Connected") +": "+address);
|
||||
wsOpen = true;
|
||||
let msg = {
|
||||
type: "Foundry"
|
||||
const msg = {
|
||||
target: "server",
|
||||
module: "MD"
|
||||
}
|
||||
ws.send(JSON.stringify(msg));
|
||||
const msg2 = {
|
||||
target: "SD",
|
||||
type: "init"
|
||||
}
|
||||
ws.send(JSON.stringify(msg2));
|
||||
clearInterval(wsInterval);
|
||||
wsInterval = setInterval(resetWS, 5000);
|
||||
}
|
||||
@@ -167,28 +180,31 @@ export function sendWS(txt){
|
||||
*/
|
||||
Hooks.once('ready', ()=>{
|
||||
enableModule = (game.settings.get(moduleName,'Enable')) ? true : false;
|
||||
if (enableModule == false) return;
|
||||
|
||||
|
||||
game.socket.on(`module.MaterialDeck`, (payload) =>{
|
||||
//console.log(payload);
|
||||
if (payload.msgType != "playSound") return;
|
||||
playTrack(payload.trackNr,payload.play,payload.repeat,payload.volume);
|
||||
playTrack(payload.trackNr,payload.src,payload.play,payload.repeat,payload.volume);
|
||||
});
|
||||
|
||||
for (let i=0; i<64; i++)
|
||||
activeSounds[i] = false;
|
||||
|
||||
if (enableModule == false) return;
|
||||
if (game.user.isGM == false) {
|
||||
ready = true;
|
||||
return;
|
||||
}
|
||||
|
||||
startWebsocket();
|
||||
|
||||
soundboard = new SoundboardControl();
|
||||
streamDeck = new StreamDeck();
|
||||
tokenControl = new TokenControl();
|
||||
move = new Move();
|
||||
macroControl = new MacroControl();
|
||||
combatTracker = new CombatTracker();
|
||||
playlistControl = new PlaylistControl();
|
||||
soundboard = new SoundboardControl();
|
||||
otherControls = new OtherControls();
|
||||
|
||||
|
||||
@@ -221,18 +237,9 @@ Hooks.once('ready', ()=>{
|
||||
|
||||
});
|
||||
|
||||
export function playTrack(soundNr,play,repeat,volume){
|
||||
export function playTrack(soundNr,src,play,repeat,volume){
|
||||
if (play){
|
||||
let trackId = game.settings.get(moduleName,'soundboardSettings').sounds[soundNr];
|
||||
let playlistId = game.settings.get(moduleName,'soundboardSettings').playlist;
|
||||
let sounds = game.playlists.entities.find(p => p._id == playlistId).data.sounds;
|
||||
let sound = sounds.find(p => p._id == trackId);
|
||||
if (sound == undefined){
|
||||
activeSounds[soundNr] = false;
|
||||
return;
|
||||
}
|
||||
volume *= game.settings.get("core", "globalInterfaceVolume");
|
||||
let src = sound.path;
|
||||
|
||||
let howl = new Howl({src, volume, loop: repeat, onend: (id)=>{
|
||||
if (repeat == false){
|
||||
@@ -247,6 +254,7 @@ export function playTrack(soundNr,play,repeat,volume){
|
||||
}
|
||||
else {
|
||||
activeSounds[soundNr].stop();
|
||||
activeSounds[soundNr] = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,6 +284,7 @@ Hooks.on('renderHotbar', (hotbar)=>{
|
||||
Hooks.on('renderCombatTracker',()=>{
|
||||
if (enableModule == false || ready == false) return;
|
||||
combatTracker.updateAll();
|
||||
tokenControl.update(selectedTokenId);
|
||||
});
|
||||
|
||||
Hooks.on('renderPlaylistDirectory', (playlistDirectory)=>{
|
||||
@@ -309,6 +318,36 @@ Hooks.on('renderSceneControls',()=>{
|
||||
otherControls.updateAll();
|
||||
});
|
||||
|
||||
Hooks.on('targetToken',(user,token,targeted)=>{
|
||||
if (enableModule == false || ready == false) return;
|
||||
if (token.id == selectedTokenId) tokenControl.update(selectedTokenId);
|
||||
});
|
||||
|
||||
Hooks.on('sidebarCollapse',()=>{
|
||||
if (enableModule == false || ready == false) return;
|
||||
otherControls.updateAll();
|
||||
});
|
||||
|
||||
Hooks.on('renderCompendium',()=>{
|
||||
if (enableModule == false || ready == false) return;
|
||||
otherControls.updateAll();
|
||||
});
|
||||
|
||||
Hooks.on('closeCompendium',()=>{
|
||||
if (enableModule == false || ready == false) return;
|
||||
otherControls.updateAll();
|
||||
});
|
||||
|
||||
Hooks.on('renderJournalSheet',()=>{
|
||||
if (enableModule == false || ready == false) return;
|
||||
otherControls.updateAll();
|
||||
});
|
||||
|
||||
Hooks.on('closeJournalSheet',()=>{
|
||||
if (enableModule == false || ready == false) return;
|
||||
otherControls.updateAll();
|
||||
});
|
||||
|
||||
Hooks.once('init', ()=>{
|
||||
//CONFIG.debug.hooks = true;
|
||||
registerSettings(); //in ./src/settings.js
|
||||
@@ -330,6 +369,21 @@ export function getFromJSONArray(data,i){
|
||||
else if (i == 6) val = data.g;
|
||||
else if (i == 7) val = data.h;
|
||||
else if (i == 8) val = data.i;
|
||||
else if (i == 9) val = data.j;
|
||||
else if (i == 10) val = data.k;
|
||||
else if (i == 11) val = data.l;
|
||||
else if (i == 12) val = data.m;
|
||||
else if (i == 13) val = data.n;
|
||||
else if (i == 14) val = data.o;
|
||||
else if (i == 15) val = data.p;
|
||||
else if (i == 16) val = data.q;
|
||||
else if (i == 17) val = data.r;
|
||||
else if (i == 18) val = data.s;
|
||||
else if (i == 19) val = data.t;
|
||||
else if (i == 20) val = data.u;
|
||||
else if (i == 21) val = data.v;
|
||||
else if (i == 22) val = data.w;
|
||||
else if (i == 23) val = data.x;
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -344,4 +398,19 @@ export function setToJSONArray(data,i,val){
|
||||
else if (i == 6) data.g = val;
|
||||
else if (i == 7) data.h = val;
|
||||
else if (i == 8) data.i = val;
|
||||
else if (i == 9) data.j = val;
|
||||
else if (i == 10) data.k = val;
|
||||
else if (i == 11) data.l = val;
|
||||
else if (i == 12) data.m = val;
|
||||
else if (i == 13) data.n = val;
|
||||
else if (i == 14) data.o = val;
|
||||
else if (i == 15) data.p = val;
|
||||
else if (i == 16) data.q = val;
|
||||
else if (i == 17) data.r = val;
|
||||
else if (i == 18) data.s = val;
|
||||
else if (i == 19) data.t = val;
|
||||
else if (i == 20) data.u = val;
|
||||
else if (i == 21) data.v = val;
|
||||
else if (i == 22) data.w = val;
|
||||
else if (i == 23) data.x = val;
|
||||
}
|
||||
12
README.md
@@ -0,0 +1,12 @@
|
||||
# Stream Deck
|
||||
Material Deck is a Foundry VTT module that allows you to control certain Foundry functions using an Elgato Stream Deck.
|
||||
|
||||
## Instructions
|
||||
Instructions are on the <a href="https://github.com/CDeenen/MaterialDeck/wiki">wiki</a>.
|
||||
|
||||
## Latest releases
|
||||
<a href="https://github.com/CDeenen/MaterialDeck/releases">Module</a><br>
|
||||
<a href="https://github.com/CDeenen/MaterialDeck_SD/releases">Stream Deck</a><br>
|
||||
<a href="https://github.com/CDeenen/MaterialServer/releases">Server</a><br>
|
||||
<br>
|
||||
Module manifest: https://raw.githubusercontent.com/CDeenen/MaterialDeck/Master/module.json
|
||||
|
||||
71
changelog.md
@@ -0,0 +1,71 @@
|
||||
# Changelog Material Deck Module
|
||||
### v0.8.7 - 19-11-2020
|
||||
<ul>
|
||||
<li>Added support for more playlists</li>
|
||||
<li>Added playmode setting for each playlist, which overrides the default playmode</li>
|
||||
<li>Added option to use the file picker to select Soundboard sounds, including support for wildcard names</li>
|
||||
<li>Fixed issue where macro config screen would not close if the module was disabled</li>
|
||||
<li>Fixed issue where the layout of the configuration screens would be messed up depending on browser/screen size</li>
|
||||
<li>Added option to open compendia and journal entries</li>
|
||||
</ul>
|
||||
|
||||
<b>Compatible server app and SD plugin:</b><br>
|
||||
Material Server v1.0.1: https://github.com/CDeenen/MaterialServer/releases <br>
|
||||
SD plugin v0.9.0: https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||
|
||||
### v0.8.6 - 18-11-2020
|
||||
<ul>
|
||||
<li>Added support for the new Material Server app</li>
|
||||
</ul>
|
||||
|
||||
<b>Compatible server app and SD plugin:</b><br>
|
||||
Material Server v1.0.0: https://github.com/CDeenen/MaterialServer/releases <br>
|
||||
SD plugin v0.7.3: https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||
|
||||
### v0.8.5 - 17-11-2020
|
||||
<ul>
|
||||
<li>Added 'Display Icon' to Macro action</li>
|
||||
<li>Removed background option from 'Macro' => 'Macro Board' => 'Trigger Macro', this is handled in the macro configuration screen</li>
|
||||
<li>Added 'Background' option in 'Macro' => 'Macro Board' => 'Offset'</li>
|
||||
<li>Fixed control buttons from not performing action when clicked</li>
|
||||
<li>Added check for each function to prevent unnecessary searching through the button buffer</li>
|
||||
<li>Added 'Target', 'Visibility', 'Toggle Combat State' and 'Set Condition' options to the 'Token' action (under 'on click')</li>
|
||||
<li>Added 'Zoom In' and 'Zoom Out' functions to 'Move' action</li>
|
||||
<li>Added ability to load icons from web sources</li>
|
||||
<li>Added support for localization (module only)</li>
|
||||
<li>Fixed issue where SD buttons would not load properly if Foundry was initialized before the SD, or if Foundry was refreshed</li>
|
||||
<li>Long words now split up onto multiple lines</li>
|
||||
<li>Confirmed compatibility with Foundry v0.7.7</li>
|
||||
</ul>
|
||||
<b>Compatible server app and SD plugin:</b><br>
|
||||
Server v0.2.4 (no change)<br>
|
||||
SD plugin v0.7.2<br>
|
||||
|
||||
### v0.8.4 - 11-11-2020
|
||||
<ul>
|
||||
<li>In 'Other' action, 'Control Button' mode, add 'Displayed Controls' option</li>
|
||||
<li>Change 'Other', 'Playlist' and 'Soundboard' actions from background color change to ring color</li>
|
||||
<li>Macro board fixed</li>
|
||||
<li>Added proper background color options for 'Other' action</li>
|
||||
<li>In 'Other' action, control button icons are now properly centered</li>
|
||||
<li>Newly created actions now show the correct options at the start</li>
|
||||
</ul>
|
||||
<b>Compatible server app and SD plugin:</b><br>
|
||||
Server v0.2.4 (no change)<br>
|
||||
SD plugin v0.7.1<br>
|
||||
|
||||
### v0.8.3 - 10-11-2020
|
||||
<ul>
|
||||
<li>Fixed compatibility with tokenizer</li>
|
||||
</ul>
|
||||
<b>Compatible server app and SD plugin:</b><br>
|
||||
Server v0.2.4<br>
|
||||
SD plugin v0.7.0<br>
|
||||
|
||||
### v0.8.2 - 10-11-2020
|
||||
<ul>
|
||||
<li>Initial beta release</li>
|
||||
</ul>
|
||||
<b>Compatible server app and SD plugin:</b><br>
|
||||
Server v0.2.4<br>
|
||||
SD plugin v0.7.1<br>
|
||||
70
lang/en.json
@@ -1,39 +1,45 @@
|
||||
{
|
||||
"MaterialDeck.Notifications.Disconnected": "Disconnected from mdServer, attempting to reconnect",
|
||||
"MaterialDeck.Notifications.ConnectFail": "Can't connect to mdServer, retrying",
|
||||
"MaterialDeck.Notifications.Disconnected": "Disconnected from Material Server, attempting to reconnect",
|
||||
"MaterialDeck.Notifications.ConnectFail": "Can't connect to Material Server, retrying",
|
||||
"MaterialDeck.Notifications.Connected": "Connected",
|
||||
|
||||
"MaterialDeck.Sett.PlaylistConfig": "Playlist Configuration",
|
||||
"MaterialDeck.Sett.SoundboardConfig": "Soundboard Configuration",
|
||||
"MaterialDeck.Sett.MacroConfig": "Macro Configuration",
|
||||
"MaterialDeck.Sett.Brightness": "Brightness",
|
||||
"MaterialDeck.Sett.Brightness_Hint": "LED brightness level",
|
||||
"MaterialDeck.Sett.Enable": "Enable module",
|
||||
"MaterialDeck.Sett.Model": "Stream Deck Model",
|
||||
"MaterialDeck.Sett.Model_Hint": "Reduces the amount of macros and sounds in the macro and soundboard configuration screens. Gives a better overview, but if desired it can be set to XL to get the maximum number. This doesn't influence the operation of the module.",
|
||||
"MaterialDeck.Sett.Model_Mini": "Mini",
|
||||
"MaterialDeck.Sett.Model_Normal": "Normal or Mobile",
|
||||
"MaterialDeck.Sett.Model_XL": "XL",
|
||||
"MaterialDeck.Sett.PlaylistConfig": "Playlist Configuration",
|
||||
"MaterialDeck.Sett.MacroConfig": "Macro Configuration",
|
||||
"MaterialDeck.Sett.SoundboardConfig": "Soundboard Configuration",
|
||||
"MaterialDeck.Sett.ServerAddr": "Material Server Address",
|
||||
"MaterialDeck.Sett.ServerAddrHint": "Fill in the IP address and port of the Material Server. Must follow the format [ip_address]:[port], for example: 'localhost:3001' or '192.168.1.1:4000'.",
|
||||
|
||||
"MaterialDeck.Playlist.Clear": "Clear data",
|
||||
"MaterialDeck.Playlist.Playmethod.Header": "Play Method",
|
||||
"MaterialDeck.Playlist.Playmethod.Label": "Method",
|
||||
"MaterialDeck.Playlist.Playmethod.Unrestricted": "Unrestricted",
|
||||
"MaterialDeck.Playlist.Playmethod.OneTrackPlaylist": "One track per playlist",
|
||||
"MaterialDeck.Playlist.Playmethod.OneTrackTotal": "One track in total",
|
||||
"MaterialDeck.Playlist.Playlists": "Playlists",
|
||||
"MaterialDeck.Playlist.Playlist": "Playlist",
|
||||
"MaterialDeck.Playlist.None": "None",
|
||||
"MaterialDeck.Playlist.Save": "Save",
|
||||
"MaterialDeck.Soundboard.Volume": "Volume",
|
||||
"MaterialDeck.PL.Unrestricted": "Unrestricted",
|
||||
"MaterialDeck.PL.OneTrackPlaylist": "One track per playlist",
|
||||
"MaterialDeck.PL.OneTrackTotal": "One track in total",
|
||||
"MaterialDeck.PL.OneTrack": "One track",
|
||||
"MaterialDeck.PL.Settings": "Settings",
|
||||
"MaterialDeck.PL.Mode": "Default Playmode",
|
||||
"MaterialDeck.PL.Nr": "Number of playlists",
|
||||
|
||||
"MaterialDeck.Soundboard.Sound": "Sound",
|
||||
"MaterialDeck.Soundboard.Icon": "Icon",
|
||||
"MaterialDeck.Soundboard.Playback": "Playback",
|
||||
"MaterialDeck.Soundboard.Once": "Once",
|
||||
"MaterialDeck.Soundboard.Repeat": "Repeat",
|
||||
"MaterialDeck.Soundboard.Hold": "Hold",
|
||||
"MaterialDeck.Soundboard.On": "On",
|
||||
"MaterialDeck.Soundboard.Off": "Off",
|
||||
|
||||
"MaterialDeck.Macro.Macro": "Macro",
|
||||
"MaterialDeck.Macro.Background": "Background",
|
||||
"MaterialDeck.Macro.FurnaceArgs": "Furnace arguments",
|
||||
|
||||
"MaterialDeck.Name": "Name"
|
||||
"MaterialDeck.Playlists": "Playlists",
|
||||
"MaterialDeck.Playlist": "Playlist",
|
||||
"MaterialDeck.FilePicker": "File Picker",
|
||||
"MaterialDeck.FurnaceArgs": "Furnace arguments",
|
||||
"MaterialDeck.Background": "Background",
|
||||
"MaterialDeck.Macro": "Macro",
|
||||
"MaterialDeck.Sound": "Sound",
|
||||
"MaterialDeck.Icon": "Icon",
|
||||
"MaterialDeck.Once": "Once",
|
||||
"MaterialDeck.Repeat": "Repeat",
|
||||
"MaterialDeck.Hold": "Hold",
|
||||
"MaterialDeck.Playback": "Playback",
|
||||
"MaterialDeck.Volume": "Volume",
|
||||
"MaterialDeck.On": "On",
|
||||
"MaterialDeck.Off": "Off",
|
||||
"MaterialDeck.Name": "Name",
|
||||
"MaterialDeck.None": "None",
|
||||
"MaterialDeck.Save": "Save"
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
"name": "MaterialDeck",
|
||||
"title": "Material Deck",
|
||||
"description": "",
|
||||
"version": "0.8.2",
|
||||
"version": "0.9.0",
|
||||
"author": "CDeenen",
|
||||
"esmodules": [
|
||||
"./MaterialDeck.js"
|
||||
],
|
||||
"socket": true,
|
||||
"minimumCoreVersion": "0.7.5",
|
||||
"compatibleCoreVersion": "0.7.6",
|
||||
"compatibleCoreVersion": "0.7.7",
|
||||
"languages": [
|
||||
{
|
||||
"lang": "en",
|
||||
@@ -18,6 +18,6 @@
|
||||
}
|
||||
],
|
||||
"url": "https://github.com/CDeenen/MaterialDeck",
|
||||
"manifest": "https://raw.githubusercontent.com/CDeenen/MaterialDeck/master/module.json",
|
||||
"download": "https://github.com/CDeenen/MaterialDeck/archive/master.zip"
|
||||
"manifest": "https://raw.githubusercontent.com/CDeenen/MaterialDeck/Master/module.json",
|
||||
"download": "https://github.com/CDeenen/MaterialDeck/archive/Master.zip"
|
||||
}
|
||||
@@ -3,11 +3,12 @@ import {streamDeck, tokenControl} from "../MaterialDeck.js";
|
||||
|
||||
export class CombatTracker{
|
||||
constructor(){
|
||||
this.active = false;
|
||||
this.combatantLength = 0;
|
||||
}
|
||||
|
||||
async updateAll(){
|
||||
|
||||
if (this.active == false) return;
|
||||
for (let i=0; i<32; i++){
|
||||
let data = streamDeck.buttonContext[i];
|
||||
if (data == undefined || data.action != 'combattracker') continue;
|
||||
@@ -16,6 +17,7 @@ export class CombatTracker{
|
||||
}
|
||||
|
||||
update(settings,context){
|
||||
this.active = true;
|
||||
let ctFunction = settings.combatTrackerFunction;
|
||||
if (ctFunction == undefined) ctFunction == 0;
|
||||
|
||||
|
||||
41
src/macro.js
@@ -3,10 +3,12 @@ import {streamDeck} from "../MaterialDeck.js";
|
||||
|
||||
export class MacroControl{
|
||||
constructor(){
|
||||
this.active = false;
|
||||
this.offset = 0;
|
||||
}
|
||||
|
||||
async updateAll(){
|
||||
if (this.active == false) return;
|
||||
for (let i=0; i<32; i++){
|
||||
let data = streamDeck.buttonContext[i];
|
||||
if (data == undefined || data.action != 'macro') continue;
|
||||
@@ -15,10 +17,15 @@ export class MacroControl{
|
||||
}
|
||||
|
||||
update(settings,context){
|
||||
this.active = true;
|
||||
let mode = settings.macroMode;
|
||||
let displayName = settings.displayName;
|
||||
let macroNumber = settings.macroNumber;
|
||||
let background = settings.background;
|
||||
let icon = false;
|
||||
if (settings.displayIcon) icon = true;
|
||||
let ringColor = "#000000";
|
||||
let ring = 0;
|
||||
if(macroNumber == undefined || isNaN(parseInt(macroNumber))){
|
||||
macroNumber = 0;
|
||||
}
|
||||
@@ -51,15 +58,15 @@ export class MacroControl{
|
||||
src += macro.img;
|
||||
}
|
||||
}
|
||||
|
||||
streamDeck.setIcon(1,context,src,background);
|
||||
if (icon) streamDeck.setIcon(1,context,src,background);
|
||||
else streamDeck.setIcon(0, context, "", background);
|
||||
if (displayName == 0) name = "";
|
||||
streamDeck.setTitle(name,context);
|
||||
}
|
||||
else {
|
||||
else { //Macro board
|
||||
let name = "";
|
||||
let src = '';
|
||||
if (settings.macroBoardMode == 0) {
|
||||
if (settings.macroBoardMode == 0) { //Execute macro
|
||||
macroNumber += this.offset - 1;
|
||||
if (macroNumber < 0) macroNumber = 0;
|
||||
var macroId = game.settings.get(MODULE.moduleName,'macroSettings').macros[macroNumber];
|
||||
@@ -75,19 +82,23 @@ export class MacroControl{
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
src = "";
|
||||
let onBackground = settings.onBackground;
|
||||
if (onBackground == undefined) onBackground = '#00FF00';
|
||||
let offBackground = settings.offBackground;
|
||||
if (offBackground == undefined) offBackground = '#000000';
|
||||
else { //Offset
|
||||
let ringOffColor = settings.offRing;
|
||||
if (ringOffColor == undefined) ringOffColor = '#000000';
|
||||
|
||||
let ringOnColor = settings.onRing;
|
||||
if (ringOnColor == undefined) ringOnColor = '#00FF00';
|
||||
|
||||
let macroOffset = parseInt(settings.macroOffset);
|
||||
if (macroOffset == undefined || isNaN(macroOffset)) macroOffset = 0;
|
||||
|
||||
if (macroOffset == parseInt(this.offset)) background = onBackground;
|
||||
else background = offBackground;
|
||||
if (macroOffset == parseInt(this.offset)) ringColor = ringOnColor;
|
||||
else ringColor = ringOffColor;
|
||||
|
||||
ring = 2;
|
||||
}
|
||||
streamDeck.setIcon(1,context,src,background);
|
||||
if (icon) streamDeck.setIcon(1, context,src,background,ring,ringColor);
|
||||
else streamDeck.setIcon(0, context, "", background,ring,ringColor);
|
||||
if (displayName == 0) name = "";
|
||||
streamDeck.setTitle(name,context);
|
||||
}
|
||||
@@ -140,13 +151,13 @@ export class MacroControl{
|
||||
let mode = settings.macroMode;
|
||||
if (mode == undefined) mode = 0;
|
||||
|
||||
if (mode == 0 || mode == 1){
|
||||
let macroNumber = settings.macroNumber;
|
||||
if(macroNumber == undefined || isNaN(parseInt(macroNumber))){
|
||||
macroNumber = 0;
|
||||
}
|
||||
|
||||
if (mode == 0 || mode == 1)
|
||||
this.executeHotbar(macroNumber,mode);
|
||||
}
|
||||
else {
|
||||
if (settings.macroBoardMode == 0)
|
||||
this.executeBoard(macroNumber);
|
||||
|
||||
196
src/misc.js
@@ -5,6 +5,8 @@ export class playlistConfigForm extends FormApplication {
|
||||
constructor(data, options) {
|
||||
super(data, options);
|
||||
this.data = data;
|
||||
this.playlistNr;
|
||||
this.updatePlaylistNr = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -13,7 +15,7 @@ export class playlistConfigForm extends FormApplication {
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
id: "playlist-config",
|
||||
title: "Material Deck: Playlist Config",
|
||||
title: "Material Deck: "+game.i18n.localize("MaterialDeck.Sett.PlaylistConfig"),
|
||||
template: "./modules/MaterialDeck/templates/playlistConfig.html",
|
||||
classes: ["sheet"],
|
||||
width: 500
|
||||
@@ -24,26 +26,31 @@ export class playlistConfigForm extends FormApplication {
|
||||
* Provide data to the template
|
||||
*/
|
||||
getData() {
|
||||
const selectedPlaylists = game.settings.get(MODULE.moduleName,'selectedPlaylists');
|
||||
let playlistData = {};
|
||||
|
||||
for (let i=0; i<9; i++){
|
||||
let playlist;
|
||||
playlist = MODULE.getFromJSONArray(selectedPlaylists,i);
|
||||
|
||||
let selectedPlaylists = game.settings.get(MODULE.moduleName,'selectedPlaylists');
|
||||
if (selectedPlaylists == undefined) selectedPlaylists = [];
|
||||
let selectedPlaylistMethod = game.settings.get(MODULE.moduleName, 'selectedPlaylistMethod');
|
||||
if (selectedPlaylistMethod == undefined) selectedPlaylistMethod = [];
|
||||
let playlistData = [];
|
||||
let numberOfPlaylists = game.settings.get(MODULE.moduleName,'numberOfPlaylists');
|
||||
if (this.updatePlaylistNr) numberOfPlaylists = this.playlistNr;
|
||||
this.updatePlaylistNr = false;
|
||||
for (let i=0; i<numberOfPlaylists; i++){
|
||||
if (selectedPlaylists[i] == undefined) selectedPlaylists[i] = 'none';
|
||||
if (selectedPlaylistMethod[i] == undefined) selectedPlaylistMethod[i] = 0;
|
||||
let dataThis = {
|
||||
iteration: i+1,
|
||||
playlist: selectedPlaylists[i],
|
||||
playlistMethod: selectedPlaylistMethod[i],
|
||||
playlists: game.playlists.entities
|
||||
}
|
||||
MODULE.setToJSONArray(playlistData,i,dataThis);
|
||||
playlistData.push(dataThis);
|
||||
}
|
||||
|
||||
if (!this.data && selectedPlaylists) {
|
||||
this.data = selectedPlaylists;
|
||||
}
|
||||
return {
|
||||
playlists: game.playlists.entities,
|
||||
numberOfPlaylists: numberOfPlaylists,
|
||||
playlistData: playlistData,
|
||||
playMethod: game.settings.get(MODULE.moduleName,'playlistMethod')
|
||||
}
|
||||
@@ -57,14 +64,19 @@ export class playlistConfigForm extends FormApplication {
|
||||
async _updateObject(event, formData) {
|
||||
await game.settings.set(MODULE.moduleName,'selectedPlaylists', formData["selectedPlaylist"]);
|
||||
await game.settings.set(MODULE.moduleName,'playlistMethod',formData["playMethod"]);
|
||||
|
||||
await game.settings.set(MODULE.moduleName,'numberOfPlaylists',formData["plNum"]);
|
||||
await game.settings.set(MODULE.moduleName,'selectedPlaylistMethod',formData["playlistMethod"]);
|
||||
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
|
||||
const numberOfPlaylists = html.find("input[name='plNum']");
|
||||
numberOfPlaylists.on("change", event => {
|
||||
this.playlistNr = event.target.value;
|
||||
this.updatePlaylistNr = true;
|
||||
this.render();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,21 +92,21 @@ export class macroConfigForm extends FormApplication {
|
||||
* Default Options for this FormApplication
|
||||
*/
|
||||
static get defaultOptions() {
|
||||
/*
|
||||
let streamDeckModel = game.settings.get(MODULE.moduleName,'streamDeckModel');
|
||||
let width;
|
||||
if (streamDeckModel == 0)
|
||||
width = 500;
|
||||
width = 550;
|
||||
else if (streamDeckModel == 1)
|
||||
width= 800;
|
||||
width= 885;
|
||||
else
|
||||
width = 1400;
|
||||
|
||||
*/
|
||||
return mergeObject(super.defaultOptions, {
|
||||
id: "macro-config",
|
||||
title: "Material Deck: "+game.i18n.localize("MaterialDeck.Sett.MacroConfig"),
|
||||
template: "./modules/MaterialDeck/templates/macroConfig.html",
|
||||
classes: ["sheet"],
|
||||
width: width
|
||||
classes: ["sheet"]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -108,7 +120,7 @@ export class macroConfigForm extends FormApplication {
|
||||
if (selectedMacros == undefined) selectedMacros = [];
|
||||
if (color == undefined) color = [];
|
||||
if (args == undefined) args = [];
|
||||
let macroData = {};
|
||||
let macroData = [];
|
||||
let furnaceEnabled = false;
|
||||
let furnace = game.modules.get("furnace");
|
||||
if (furnace != undefined && furnace.active) furnaceEnabled = true;
|
||||
@@ -132,7 +144,7 @@ export class macroConfigForm extends FormApplication {
|
||||
|
||||
let iteration = 0;
|
||||
for (let j=0; j<jMax; j++){
|
||||
let macroThis = {};
|
||||
let macroThis = [];
|
||||
|
||||
for (let i=0; i<iMax; i++){
|
||||
let colorThis = color[iteration];
|
||||
@@ -156,13 +168,13 @@ export class macroConfigForm extends FormApplication {
|
||||
args: args[iteration],
|
||||
furnace: furnaceEnabled
|
||||
}
|
||||
MODULE.setToJSONArray(macroThis,i,dataThis);
|
||||
macroThis.push(dataThis);
|
||||
iteration++;
|
||||
}
|
||||
let data = {
|
||||
dataThis: macroThis,
|
||||
};
|
||||
MODULE.setToJSONArray(macroData,j,data);
|
||||
macroData.push(data);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -187,6 +199,7 @@ export class macroConfigForm extends FormApplication {
|
||||
let furnace = game.modules.get("furnace");
|
||||
if (furnace != undefined && furnace.active)
|
||||
await game.settings.set(MODULE.moduleName,'macroArgs', formData["args"]);
|
||||
if (MODULE.enableModule)
|
||||
macroControl.updateAll();
|
||||
}
|
||||
|
||||
@@ -202,7 +215,7 @@ export class soundboardConfigForm extends FormApplication {
|
||||
super(data, options);
|
||||
this.data = data;
|
||||
//this.soundData = {};
|
||||
this.playlist;
|
||||
this.playlists = [];
|
||||
this.updatePlaylist = false;
|
||||
}
|
||||
|
||||
@@ -210,21 +223,21 @@ export class soundboardConfigForm extends FormApplication {
|
||||
* Default Options for this FormApplication
|
||||
*/
|
||||
static get defaultOptions() {
|
||||
/*
|
||||
let streamDeckModel = game.settings.get(MODULE.moduleName,'streamDeckModel');
|
||||
let width;
|
||||
if (streamDeckModel == 0)
|
||||
width = 500;
|
||||
width = 550;
|
||||
else if (streamDeckModel == 1)
|
||||
width= 800;
|
||||
width= 885;
|
||||
else
|
||||
width = 1400;
|
||||
|
||||
*/
|
||||
return mergeObject(super.defaultOptions, {
|
||||
id: "soundboard-config",
|
||||
title: "Material Deck: "+game.i18n.localize("MaterialDeck.Sett.SoundboardConfig"),
|
||||
template: "./modules/MaterialDeck/templates/soundboardConfig.html",
|
||||
classes: ["sheet"],
|
||||
width: width,
|
||||
height: 720
|
||||
});
|
||||
}
|
||||
@@ -238,16 +251,6 @@ export class soundboardConfigForm extends FormApplication {
|
||||
* Provide data to the template
|
||||
*/
|
||||
getData() {
|
||||
let playlistId = game.settings.get(MODULE.moduleName,'soundboardSettings').playlist;
|
||||
if (this.updatePlaylist) playlistId = this.playlist;
|
||||
this.updatePlaylist = false;
|
||||
let playlist = 'none';
|
||||
let sounds = [];
|
||||
if (playlistId != undefined){
|
||||
playlist = game.playlists.entities.find(p => p._id == playlistId);
|
||||
if (playlist != undefined) sounds = playlist.sounds;
|
||||
else playlist = 'none';
|
||||
}
|
||||
let selectedSounds = game.settings.get(MODULE.moduleName,'soundboardSettings').sounds;
|
||||
let colorOn = game.settings.get(MODULE.moduleName,'soundboardSettings').colorOn;
|
||||
let colorOff = game.settings.get(MODULE.moduleName,'soundboardSettings').colorOff;
|
||||
@@ -255,6 +258,15 @@ export class soundboardConfigForm extends FormApplication {
|
||||
let volume = game.settings.get(MODULE.moduleName,'soundboardSettings').volume;
|
||||
let img = game.settings.get(MODULE.moduleName,'soundboardSettings').img;
|
||||
let name = game.settings.get(MODULE.moduleName,'soundboardSettings').name;
|
||||
let selectedPlaylists = game.settings.get(MODULE.moduleName,'soundboardSettings').selectedPlaylists;
|
||||
let src = game.settings.get(MODULE.moduleName,'soundboardSettings').src;
|
||||
|
||||
let playlists = [];
|
||||
playlists.push({id:"none",name:game.i18n.localize("MaterialDeck.None")});
|
||||
playlists.push({id:"FP",name:game.i18n.localize("MaterialDeck.FilePicker")})
|
||||
for (let i=0; i<game.playlists.entities.length; i++){
|
||||
playlists.push({id:game.playlists.entities[i]._id,name:game.playlists.entities[i].name});
|
||||
}
|
||||
|
||||
if (selectedSounds == undefined) selectedSounds = [];
|
||||
if (colorOn == undefined) colorOn = [];
|
||||
@@ -262,7 +274,9 @@ export class soundboardConfigForm extends FormApplication {
|
||||
if (mode == undefined) mode = [];
|
||||
if (img == undefined) img = [];
|
||||
if (name == undefined) name = [];
|
||||
let soundData = {};
|
||||
if (selectedPlaylists == undefined) selectedPlaylists = [];
|
||||
if (src == undefined) src = [];
|
||||
let soundData = [];
|
||||
|
||||
let streamDeckModel = game.settings.get(MODULE.moduleName,'streamDeckModel');
|
||||
let iMax,jMax;
|
||||
@@ -279,40 +293,58 @@ export class soundboardConfigForm extends FormApplication {
|
||||
iMax = 8;
|
||||
}
|
||||
|
||||
if (this.updatePlaylist) selectedPlaylists = this.playlists;
|
||||
else this.playlists = selectedPlaylists;
|
||||
this.updatePlaylist = false;
|
||||
|
||||
let iteration = 0;
|
||||
|
||||
for (let j=0; j<jMax; j++){
|
||||
let soundsThis = {};
|
||||
let soundsThis = [];
|
||||
for (let i=0; i<iMax; i++){
|
||||
let selectedPlaylist;
|
||||
let sounds = [];
|
||||
if (volume == undefined) volume = 50;
|
||||
|
||||
|
||||
if (selectedPlaylists[iteration]==undefined) selectedPlaylist = 'none';
|
||||
else if (selectedPlaylists[iteration] == 'none') selectedPlaylist = 'none';
|
||||
else if (selectedPlaylists[iteration] == 'FP') selectedPlaylist = 'FP';
|
||||
else {
|
||||
const pl = game.playlists.entities.find(p => p._id == selectedPlaylists[iteration]);
|
||||
selectedPlaylist = pl._id;
|
||||
sounds = pl.sounds;
|
||||
}
|
||||
let styleSS = "";
|
||||
let styleFP ="display:none";
|
||||
if (selectedPlaylist == 'FP') {
|
||||
styleSS = 'display:none';
|
||||
styleFP = ''
|
||||
}
|
||||
let dataThis = {
|
||||
iteration: iteration+1,
|
||||
playlists: playlists,
|
||||
selectedPlaylist: selectedPlaylist,
|
||||
sound: selectedSounds[iteration],
|
||||
sounds: sounds,
|
||||
srcPath: src[iteration],
|
||||
colorOn: colorOn[iteration],
|
||||
colorOff: colorOff[iteration],
|
||||
mode: mode[iteration],
|
||||
volume: volume[iteration],
|
||||
imgPath: img[iteration],
|
||||
name: name[iteration]
|
||||
name: name[iteration],
|
||||
styleSS: styleSS,
|
||||
styleFP: styleFP
|
||||
}
|
||||
MODULE.setToJSONArray(soundsThis,i,dataThis);
|
||||
soundsThis.push(dataThis);
|
||||
iteration++;
|
||||
}
|
||||
let data = {
|
||||
dataThis: soundsThis,
|
||||
};
|
||||
MODULE.setToJSONArray(soundData,j,data);
|
||||
|
||||
soundData.push(data);
|
||||
}
|
||||
return {
|
||||
playlists: game.playlists.entities,
|
||||
playlist: playlistId,
|
||||
sounds: sounds,
|
||||
selectedSound81: selectedSounds.a,
|
||||
soundData: soundData,
|
||||
soundData: soundData
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,86 +356,42 @@ export class soundboardConfigForm extends FormApplication {
|
||||
async _updateObject(event, formData) {
|
||||
let length = formData["sounds"].length;
|
||||
let img = [];
|
||||
let soundSrc = []
|
||||
for (let i=0; i<length; i++){
|
||||
let name = "img"+(i+1);
|
||||
let src = formData[name];
|
||||
img[i] = src;
|
||||
|
||||
name = "src"+(i+1);
|
||||
src = formData[name];
|
||||
soundSrc[i] = src;
|
||||
}
|
||||
|
||||
await game.settings.set(MODULE.moduleName,'soundboardSettings',{
|
||||
playlist: formData["playlist"],
|
||||
selectedPlaylists: formData["playlist"],
|
||||
sounds: formData["sounds"],
|
||||
colorOn: formData["colorOn"],
|
||||
colorOff: formData["colorOff"],
|
||||
mode: formData["mode"],
|
||||
img: img,
|
||||
volume: formData["volume"],
|
||||
name: formData["name"]
|
||||
name: formData["name"],
|
||||
src: soundSrc
|
||||
});
|
||||
//MODULE.launchpad.audioSoundboardUpdate();
|
||||
}
|
||||
|
||||
async activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
const colorPickerOn = html.find("button[name='colorPickerOn']");
|
||||
const colorPickerOff = html.find("button[name='colorPickerOff']");
|
||||
const playlistSelect = html.find("select[name='playlist']");
|
||||
const volumeSlider = html.find("input[name='volume']");
|
||||
const soundSelect = html.find("select[name='sounds']");
|
||||
|
||||
/*
|
||||
colorPickerOn.on('click',(event) => {
|
||||
let target = event.currentTarget.value;
|
||||
let color = document.getElementById("colorOn"+target).value;
|
||||
if ((color < 0 && color > 127) || color == "") color = 0;
|
||||
MODULE.launchpad.colorPicker(target,1,color);
|
||||
|
||||
});
|
||||
colorPickerOff.on('click',(event) => {
|
||||
let target = event.currentTarget.value;
|
||||
let color = document.getElementById("colorOff"+target).value;
|
||||
if ((color < 0 && color > 127) || color == "") color = 0;
|
||||
MODULE.launchpad.colorPicker(target,0,color);
|
||||
|
||||
});
|
||||
if (playlistSelect.length > 0) {
|
||||
playlistSelect.on("change", event => {
|
||||
this.playlist = event.target.value;
|
||||
let id = event.target.id.replace('playlists','');
|
||||
this.playlists[id-1] = event.target.value;
|
||||
this.updatePlaylist = true;
|
||||
this.render();
|
||||
});
|
||||
}
|
||||
volumeSlider.on('change', event => {
|
||||
let id = event.target.id.replace('volume','');
|
||||
let column = id%10-1;
|
||||
let row = 8-Math.floor(id/10);
|
||||
id = row*8+column;
|
||||
let settings = game.settings.get(MODULE.moduleName,'soundboardSettings');
|
||||
settings.volume[id] = event.target.value;
|
||||
game.settings.set(MODULE.moduleName,'soundboardSettings',settings);
|
||||
if (MODULE.launchpad.activeSounds[id] != false){
|
||||
let volume = AudioHelper.inputToVolume(event.target.value/100) * game.settings.get("core", "globalInterfaceVolume");
|
||||
MODULE.launchpad.activeSounds[id].volume(volume);
|
||||
}
|
||||
});
|
||||
if (soundSelect.length > 0) {
|
||||
soundSelect.on("change",event => {
|
||||
let id = event.target.id.replace('soundSelect','');
|
||||
let column = id%10-1;
|
||||
let row = 8-Math.floor(id/10);
|
||||
id = row*8+column;
|
||||
let settings = game.settings.get(MODULE.moduleName,'soundboardSettings');
|
||||
settings.sounds[id] = event.target.value;
|
||||
game.settings.set(MODULE.moduleName,'soundboardSettings',settings);
|
||||
if (MODULE.launchpad.activeSounds[id] != false){
|
||||
let mode = settings.mode[id];
|
||||
let repeat = false;
|
||||
if (mode == 1) repeat = true;
|
||||
MODULE.launchpad.playSound(id,repeat,false);
|
||||
}
|
||||
});
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
17
src/move.js
@@ -2,22 +2,37 @@ import * as MODULE from "../MaterialDeck.js";
|
||||
|
||||
export class Move{
|
||||
constructor(){
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
keyPress(settings){
|
||||
console.log('move',settings)
|
||||
let dir = settings.dir;
|
||||
let mode = settings.mode;
|
||||
if (mode == undefined) mode = 0;
|
||||
if (dir == undefined) dir = 0;
|
||||
if (dir < 9){
|
||||
if (settings.mode == '1')
|
||||
this.moveToken(MODULE.selectedTokenId,dir);
|
||||
else
|
||||
this.moveCanvas(dir);
|
||||
}
|
||||
else if (dir == 9) {//zoom in
|
||||
let viewPosition = canvas.scene._viewPosition;
|
||||
viewPosition.scale = viewPosition.scale*1.05;
|
||||
viewPosition.duration = 100;
|
||||
canvas.animatePan(viewPosition);
|
||||
}
|
||||
else if (dir == 10) {//zoom out
|
||||
let viewPosition = canvas.scene._viewPosition;
|
||||
viewPosition.scale = viewPosition.scale*0.95;
|
||||
viewPosition.duration = 100;
|
||||
canvas.animatePan(viewPosition);
|
||||
}
|
||||
}
|
||||
|
||||
async moveToken(tokenId,dir){
|
||||
if (tokenId == undefined) return;
|
||||
|
||||
const token = canvas.tokens.children[0].children.find(p => p.id == tokenId);
|
||||
const gridSize = canvas.scene.data.grid;
|
||||
let x = token.x;
|
||||
|
||||
@@ -3,10 +3,12 @@ import {streamDeck} from "../MaterialDeck.js";
|
||||
|
||||
export class OtherControls{
|
||||
constructor(){
|
||||
this.active = false;
|
||||
this.offset = 0;
|
||||
}
|
||||
|
||||
async updateAll(){
|
||||
if (this.active == false) return;
|
||||
for (let i=0; i<32; i++){
|
||||
let data = streamDeck.buttonContext[i];
|
||||
if (data == undefined || data.action != 'other') continue;
|
||||
@@ -15,6 +17,7 @@ export class OtherControls{
|
||||
}
|
||||
|
||||
update(settings,context){
|
||||
this.active = true;
|
||||
let mode = settings.otherMode;
|
||||
if (mode == undefined) mode = 0;
|
||||
|
||||
@@ -33,6 +36,15 @@ export class OtherControls{
|
||||
else if (mode == 4){ //roll tables
|
||||
this.updateRollTable(settings,context);
|
||||
}
|
||||
else if (mode == 5) { //open sidebar tab
|
||||
this.updateSidebar(settings,context);
|
||||
}
|
||||
else if (mode == 6) { //open compendium
|
||||
this.updateCompendium(settings,context);
|
||||
}
|
||||
else if (mode == 7) { //open journal
|
||||
this.updateJournal(settings,context);
|
||||
}
|
||||
}
|
||||
|
||||
keyPress(settings){
|
||||
@@ -54,30 +66,53 @@ export class OtherControls{
|
||||
else if (mode == 4) { //roll tables
|
||||
this.keyPressRollTable(settings);
|
||||
}
|
||||
else if (mode == 5) { //sidebar
|
||||
this.keyPressSidebar(settings);
|
||||
}
|
||||
else if (mode == 6) { //open compendium
|
||||
this.keyPressCompendium(settings);
|
||||
}
|
||||
else if (mode == 7) { //open journal
|
||||
this.keyPressJournal(settings);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
updatePause(pauseFunction,context){
|
||||
|
||||
if (pauseFunction == undefined) pauseFunction = 0;
|
||||
let src = "";
|
||||
let name = "";
|
||||
let background = "#000000";
|
||||
if (pauseFunction == undefined) pauseFunction = 0;
|
||||
|
||||
let background = settings.background;
|
||||
if(background == undefined) background = '#000000';
|
||||
|
||||
let ringColor = "#000000";
|
||||
|
||||
let ringOffColor = settings.offRing;
|
||||
if (ringOffColor == undefined) ringOffColor = '#000000';
|
||||
|
||||
let ringOnColor = settings.onRing;
|
||||
if (ringOnColor == undefined) ringOnColor = '#00FF00';
|
||||
|
||||
let playlistType = settings.playlistType;
|
||||
if (playlistType == undefined) playlistType = 0;
|
||||
|
||||
if (pauseFunction == 0){ //Pause game
|
||||
if (game.paused) background = "#00FF00"
|
||||
if (game.paused) ringColor = ringOnColor;
|
||||
else ringColor = ringOffColor;
|
||||
src = 'action/images/other/pause/pause.png';
|
||||
}
|
||||
else if (pauseFunction == 1){ //Resume game
|
||||
if (game.paused == false) background = "#00FF00"
|
||||
if (game.paused == false) ringColor = ringOnColor;
|
||||
else ringColor = ringOffColor;
|
||||
src = 'action/images/other/pause/resume.png';
|
||||
}
|
||||
else if (pauseFunction == 2) { //toggle
|
||||
if (game.paused == false) background = "#00FF00"
|
||||
if (game.paused == false) ringColor = ringOnColor;
|
||||
else ringColor = ringOffColor;
|
||||
src = 'action/images/other/pause/playpause.png';
|
||||
}
|
||||
streamDeck.setIcon(0,context,src,background);
|
||||
streamDeck.setTitle(name,context);
|
||||
streamDeck.setIcon(0,context,src,background,2,ringColor);
|
||||
}
|
||||
|
||||
keyPressPause(pauseFunction){
|
||||
@@ -101,56 +136,54 @@ export class OtherControls{
|
||||
let func = settings.sceneFunction;
|
||||
if (func == undefined) func = 0;
|
||||
|
||||
let background = settings.background;
|
||||
if(background == undefined) background = '#000000';
|
||||
|
||||
let ringColor = "#000000";
|
||||
|
||||
let ringOffColor = settings.offRing;
|
||||
if (ringOffColor == undefined) ringOffColor = '#000000';
|
||||
|
||||
let ringOnColor = settings.onRing;
|
||||
if (ringOnColor == undefined) ringOnColor = '#00FF00';
|
||||
|
||||
let playlistType = settings.playlistType;
|
||||
if (playlistType == undefined) playlistType = 0;
|
||||
|
||||
let src = "";
|
||||
let name = "";
|
||||
if (func == 0){ //visible scenes
|
||||
let nr = parseInt(settings.sceneNr);
|
||||
if (isNaN(nr)) nr = 1;
|
||||
nr--;
|
||||
|
||||
let background = settings.background;
|
||||
if (background == undefined) background = "#000000";
|
||||
|
||||
let scene = game.scenes.apps[0].scenes[nr];
|
||||
let name = "";
|
||||
let src = "";
|
||||
let ringColor = "#000000";
|
||||
let ring = 1;
|
||||
|
||||
if (scene != undefined){
|
||||
if (scene.isView) {
|
||||
ringColor = "#00FF00";
|
||||
ring = 2;
|
||||
}
|
||||
if (scene.isView)
|
||||
ringColor = ringOnColor;
|
||||
else
|
||||
ringColor = ringOffColor;
|
||||
if (settings.displaySceneName) name = scene.name;
|
||||
if (settings.displaySceneIcon) src = scene.img;
|
||||
if (scene.active) name += "\n(Active)";
|
||||
}
|
||||
streamDeck.setTitle(name,context);
|
||||
streamDeck.setIcon(1, context,src,background,ring,ringColor);
|
||||
|
||||
}
|
||||
else if (func == 1) { //all scenes
|
||||
let name = settings.sceneName;
|
||||
if (name == undefined) return;
|
||||
|
||||
let background = settings.background;
|
||||
if (background == undefined) background = "#000000";
|
||||
|
||||
let src = "";
|
||||
let ringColor = "#000000";
|
||||
let ring = 1;
|
||||
let scene = game.scenes.apps[1].entities.find(p=>p.data.name == name);
|
||||
name = "";
|
||||
if (scene != undefined){
|
||||
if (scene.isView) {
|
||||
ringColor = "#00FF00";
|
||||
ring = 2;
|
||||
}
|
||||
if (scene.isView)
|
||||
ringColor = ringOnColor;
|
||||
else
|
||||
ringColor = ringOffColor;
|
||||
if (settings.displaySceneName) name = scene.name;
|
||||
if (settings.displaySceneIcon) src = scene.img;
|
||||
if (scene.active) name += "\n(Active)";
|
||||
}
|
||||
streamDeck.setTitle(name,context);
|
||||
streamDeck.setIcon(1, context,src,background,ring,ringColor);
|
||||
}
|
||||
streamDeck.setTitle(name,context);
|
||||
streamDeck.setIcon(1, context,src,background,2,ringColor);
|
||||
}
|
||||
|
||||
keyPressScene(settings){
|
||||
@@ -177,9 +210,9 @@ export class OtherControls{
|
||||
scene.view();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
updateControl(settings,context){
|
||||
@@ -189,54 +222,68 @@ export class OtherControls{
|
||||
let tool = settings.tool;
|
||||
if (tool == undefined) tool = 0;
|
||||
|
||||
let background = settings.background;
|
||||
if (background == undefined) background = '#000000';
|
||||
|
||||
let ringColor = '#000000'
|
||||
|
||||
const controlName = this.getControlName(control);
|
||||
const toolName = this.getToolName(control,tool);
|
||||
|
||||
let txt = "";
|
||||
let src = "";
|
||||
let background = "#000000";
|
||||
let ringColor = "#FF7B00"
|
||||
let selectedControl;
|
||||
let selectedTool;
|
||||
let ring = 1;
|
||||
let activeControl = ui.controls.activeControl;
|
||||
let activeTool = ui.controls.activeTool;
|
||||
const activeControl = ui.controls.activeControl;
|
||||
const activeTool = ui.controls.activeTool;
|
||||
|
||||
if (control == 0){
|
||||
if (control == 0) { //displayed controls
|
||||
let controlNr = parseInt(settings.controlNr);
|
||||
if (isNaN(controlNr)) controlNr = 1;
|
||||
controlNr--;
|
||||
|
||||
selectedControl = ui.controls.controls.find(c => c.name == ui.controls.activeControl);
|
||||
if (selectedControl != undefined){
|
||||
selectedTool = selectedControl.tools[controlNr];
|
||||
if (selectedTool != undefined){
|
||||
txt = game.i18n.localize(selectedTool.title);
|
||||
src = selectedTool.icon;
|
||||
if (selectedTool.toggle){
|
||||
background = "#340057"
|
||||
if (selectedTool.active)
|
||||
ringColor = "#A600FF"
|
||||
else
|
||||
ringColor = "#340057"
|
||||
ring = 2;
|
||||
}
|
||||
else if (activeTool == selectedTool.name)
|
||||
ring = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
selectedControl = ui.controls.controls.find(c => c.name == controlName);
|
||||
const selectedControl = ui.controls.controls[controlNr];
|
||||
if (selectedControl != undefined){
|
||||
if (tool == 0){ //open category
|
||||
txt = game.i18n.localize(selectedControl.title);
|
||||
src = selectedControl.icon;
|
||||
if (activeControl == selectedControl.name)
|
||||
ring = 2;
|
||||
ringColor = "#FF7B00";
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (control == 1){ //displayed tools
|
||||
let controlNr = parseInt(settings.controlNr);
|
||||
if (isNaN(controlNr)) controlNr = 1;
|
||||
controlNr--;
|
||||
|
||||
const selectedControl = ui.controls.controls.find(c => c.name == ui.controls.activeControl);
|
||||
if (selectedControl != undefined){
|
||||
const selectedTool = selectedControl.tools[controlNr];
|
||||
if (selectedTool != undefined){
|
||||
txt = game.i18n.localize(selectedTool.title);
|
||||
src = selectedTool.icon;
|
||||
if (selectedTool.toggle){
|
||||
background = "#340057"
|
||||
if (selectedTool.active)
|
||||
ringColor = "#A600FF"
|
||||
else
|
||||
ringColor = "#340057";
|
||||
}
|
||||
else if (activeTool == selectedTool.name)
|
||||
ringColor = "#FF7B00";
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // specific control/tool
|
||||
const selectedControl = ui.controls.controls.find(c => c.name == controlName);
|
||||
if (selectedControl != undefined){
|
||||
if (tool == 0){ //open category
|
||||
txt = game.i18n.localize(selectedControl.title);
|
||||
src = selectedControl.icon;
|
||||
if (activeControl == selectedControl.name)
|
||||
ringColor = "#FF7B00";
|
||||
}
|
||||
else {
|
||||
selectedTool = selectedControl.tools.find(t => t.name == toolName);
|
||||
const selectedTool = selectedControl.tools.find(t => t.name == toolName);
|
||||
if (selectedTool != undefined){
|
||||
txt = game.i18n.localize(selectedTool.title);
|
||||
src = selectedTool.icon;
|
||||
@@ -246,15 +293,14 @@ export class OtherControls{
|
||||
ringColor = "#A600FF"
|
||||
else
|
||||
ringColor = "#340057"
|
||||
ring = 2;
|
||||
}
|
||||
else if (activeTool == selectedTool.name && activeControl == selectedControl.name)
|
||||
ring = 2;
|
||||
ringColor = "#FF7B00";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
streamDeck.setIcon(1,context,src,background,ring,ringColor);
|
||||
streamDeck.setIcon(1,context,src,background,2,ringColor);
|
||||
streamDeck.setTitle(txt,context);
|
||||
}
|
||||
|
||||
@@ -268,29 +314,39 @@ export class OtherControls{
|
||||
const controlName = this.getControlName(control);
|
||||
const toolName = this.getToolName(control,tool);
|
||||
|
||||
if (control == 0){ //displayed tools
|
||||
if (control == 0){ //displayed controls
|
||||
let controlNr = parseInt(settings.controlNr);
|
||||
if (isNaN(controlNr)) controlNr = 1;
|
||||
controlNr--;
|
||||
let selectedControl = ui.controls.controls.find(c => c.name == ui.controls.activeControl);
|
||||
const selectedControl = ui.controls.controls[controlNr];
|
||||
if (selectedControl != undefined){
|
||||
let selectedTool = selectedControl.tools[controlNr];
|
||||
ui.controls.activeControl = controlName;
|
||||
selectedControl.activeTool = selectedControl.activeTool;
|
||||
canvas.getLayer(selectedControl.layer).activate();
|
||||
}
|
||||
}
|
||||
else if (control == 1){ //displayed tools
|
||||
let controlNr = parseInt(settings.controlNr);
|
||||
if (isNaN(controlNr)) controlNr = 1;
|
||||
controlNr--;
|
||||
const selectedControl = ui.controls.controls.find(c => c.name == ui.controls.activeControl);
|
||||
if (selectedControl != undefined){
|
||||
const selectedTool = selectedControl.tools[controlNr];
|
||||
if (selectedTool != undefined){
|
||||
if (selectedTool.toggle) {
|
||||
let newValue = !selectedTool.active;
|
||||
selectedTool.active = newValue;
|
||||
selectedTool.active = !selectedTool.active;
|
||||
selectedTool.onClick(selectedTool.active);
|
||||
}
|
||||
else if (selectedTool.button){
|
||||
selectedTool.onClick();
|
||||
}
|
||||
else
|
||||
selectedControl.activeTool = selectedTool.name;
|
||||
ui.controls.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
else { //select control
|
||||
let selectedControl = ui.controls.controls.find(c => c.name == controlName);
|
||||
const selectedControl = ui.controls.controls.find(c => c.name == controlName);
|
||||
if (selectedControl != undefined){
|
||||
if (tool == 0){ //open category
|
||||
ui.controls.activeControl = controlName;
|
||||
@@ -298,13 +354,13 @@ export class OtherControls{
|
||||
canvas.getLayer(selectedControl.layer).activate();
|
||||
}
|
||||
else {
|
||||
let selectedTool = selectedControl.tools.find(t => t.name == toolName);
|
||||
const selectedTool = selectedControl.tools.find(t => t.name == toolName);
|
||||
if (selectedTool != undefined){
|
||||
ui.controls.activeControl = controlName;
|
||||
canvas.getLayer(selectedControl.layer).activate();
|
||||
if (selectedTool.toggle) {
|
||||
let newValue = !selectedTool.active;
|
||||
selectedTool.active = newValue;
|
||||
selectedTool.active = !selectedTool.active;
|
||||
selectedTool.onClick(selectedTool.active);
|
||||
}
|
||||
else if (selectedTool.button){
|
||||
selectedTool.onClick();
|
||||
@@ -313,21 +369,13 @@ export class OtherControls{
|
||||
selectedControl.activeTool = toolName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ui.controls.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//ui.controls.controls.find(c => c.name == 'token')
|
||||
//ui.controls.controls.find(c => c.name == 'walls').tools.find(t => t.name == 'snap').active=false
|
||||
//ui.controls.render()
|
||||
|
||||
getControlName(control){
|
||||
control--;
|
||||
control -= 2;
|
||||
let name;
|
||||
if (control == 0) name = 'token';
|
||||
else if (control == 1) name = 'measure';
|
||||
@@ -341,7 +389,7 @@ export class OtherControls{
|
||||
}
|
||||
|
||||
getToolName(control,tool){
|
||||
control--;
|
||||
control -= 2;
|
||||
tool--;
|
||||
let name;
|
||||
if (control == 0){ //basic controls
|
||||
@@ -498,4 +546,175 @@ export class OtherControls{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
getSidebarId(nr){
|
||||
let id;
|
||||
if (nr == 0) id = 'chat';
|
||||
else if (nr == 1) id = 'combat';
|
||||
else if (nr == 2) id = 'scenes';
|
||||
else if (nr == 3) id = 'actors';
|
||||
else if (nr == 4) id = 'items';
|
||||
else if (nr == 5) id = 'journal';
|
||||
else if (nr == 6) id = 'tables';
|
||||
else if (nr == 7) id = 'playlists';
|
||||
else if (nr == 8) id = 'compendium';
|
||||
else if (nr == 9) id = 'settings';
|
||||
else id = '';
|
||||
return id;
|
||||
}
|
||||
|
||||
getSidebarName(nr){
|
||||
let name;
|
||||
if (nr == 0) name = game.i18n.localize("SIDEBAR.TabChat");
|
||||
else if (nr == 1) name = game.i18n.localize("SIDEBAR.TabCombat");
|
||||
else if (nr == 2) name = game.i18n.localize("SIDEBAR.TabScenes");
|
||||
else if (nr == 3) name = game.i18n.localize("SIDEBAR.TabActors");
|
||||
else if (nr == 4) name = game.i18n.localize("SIDEBAR.TabItems");
|
||||
else if (nr == 5) name = game.i18n.localize("SIDEBAR.TabJournal");
|
||||
else if (nr == 6) name = game.i18n.localize("SIDEBAR.TabTables");
|
||||
else if (nr == 7) name = game.i18n.localize("SIDEBAR.TabPlaylists");
|
||||
else if (nr == 8) name = game.i18n.localize("SIDEBAR.TabCompendium");
|
||||
else if (nr == 9) name = game.i18n.localize("SIDEBAR.TabSettings");
|
||||
else if (nr == 10) name = game.i18n.localize("SIDEBAR.CollapseToggle");
|
||||
return name;
|
||||
}
|
||||
|
||||
getSidebarIcon(nr){
|
||||
let icon;
|
||||
if (nr == 0) icon = window.CONFIG.ChatMessage.sidebarIcon;
|
||||
else if (nr == 1) icon = window.CONFIG.Combat.sidebarIcon;
|
||||
else if (nr == 2) icon = window.CONFIG.Scene.sidebarIcon;
|
||||
else if (nr == 3) icon = window.CONFIG.Actor.sidebarIcon;
|
||||
else if (nr == 4) icon = window.CONFIG.Item.sidebarIcon;
|
||||
else if (nr == 5) icon = window.CONFIG.JournalEntry.sidebarIcon;
|
||||
else if (nr == 6) icon = window.CONFIG.RollTable.sidebarIcon;
|
||||
else if (nr == 7) icon = window.CONFIG.Playlist.sidebarIcon;
|
||||
else if (nr == 8) icon = "fas fa-atlas";
|
||||
else if (nr == 9) icon = "fas fa-cogs";
|
||||
else if (nr == 10) icon = "fas fa-caret-right";
|
||||
return icon;
|
||||
}
|
||||
|
||||
updateSidebar(settings,context){
|
||||
let sidebarTab = settings.sidebarTab;
|
||||
if (sidebarTab == undefined) sidebarTab = 0;
|
||||
|
||||
let activeTab = ui.sidebar.activeTab;
|
||||
let collapsed = ui.sidebar._collapsed;
|
||||
|
||||
let name = "";
|
||||
let icon = "";
|
||||
|
||||
let background = settings.background;
|
||||
if(background == undefined) background = '#000000';
|
||||
|
||||
let ringColor = "#000000";
|
||||
|
||||
let ringOffColor = settings.offRing;
|
||||
if (ringOffColor == undefined) ringOffColor = '#000000';
|
||||
|
||||
let ringOnColor = settings.onRing;
|
||||
if (ringOnColor == undefined) ringOnColor = '#00FF00';
|
||||
|
||||
if (settings.displaySidebarName) name = this.getSidebarName(sidebarTab);
|
||||
if (settings.displaySidebarIcon) icon = this.getSidebarIcon(sidebarTab);
|
||||
|
||||
if ((sidebarTab == 10 && collapsed))
|
||||
ringColor = ringOnColor;
|
||||
else
|
||||
ringColor = ringOffColor;
|
||||
streamDeck.setTitle(name,context);
|
||||
streamDeck.setIcon(1,context,icon,background,2,ringColor);
|
||||
}
|
||||
|
||||
keyPressSidebar(settings){
|
||||
let sidebarTab = settings.sidebarTab;
|
||||
if (sidebarTab == undefined) sidebarTab = 0;
|
||||
let collapsed = ui.sidebar._collapsed;
|
||||
|
||||
if (sidebarTab < 10) ui.sidebar.activateTab(this.getSidebarId(sidebarTab));
|
||||
else if (collapsed) ui.sidebar.expand();
|
||||
else if (collapsed == false) ui.sidebar.collapse();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
updateCompendium(settings,context){
|
||||
let background = settings.background;
|
||||
if(background == undefined) background = '#000000';
|
||||
|
||||
let name = settings.compendiumName;
|
||||
if (name == undefined) return;
|
||||
|
||||
const compendium = game.packs.entries.find(p=>p.metadata.label == name);
|
||||
if (compendium == undefined) return;
|
||||
|
||||
let ringColor = "#000000";
|
||||
|
||||
let ringOffColor = settings.offRing;
|
||||
if (ringOffColor == undefined) ringOffColor = '#000000';
|
||||
|
||||
let ringOnColor = settings.onRing;
|
||||
if (ringOnColor == undefined) ringOnColor = '#00FF00';
|
||||
|
||||
|
||||
if (compendium.rendered) ringColor = ringOnColor;
|
||||
else ringColor = ringOffColor;
|
||||
|
||||
if (settings.displayCompendiumName) streamDeck.setTitle(name,context);
|
||||
streamDeck.setIcon(0,context,"",background,2,ringColor);
|
||||
}
|
||||
|
||||
keyPressCompendium(settings){
|
||||
let name = settings.compendiumName;
|
||||
if (name == undefined) return;
|
||||
|
||||
const compendium = game.packs.entries.find(p=>p.metadata.label == name);
|
||||
if (compendium == undefined) return;
|
||||
if (compendium.rendered) compendium.close();
|
||||
else compendium.render(true);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//Journals
|
||||
//game.journal.entries[0].render(true)
|
||||
|
||||
updateJournal(settings,context){
|
||||
let background = settings.background;
|
||||
if(background == undefined) background = '#000000';
|
||||
|
||||
let name = settings.compendiumName;
|
||||
if (name == undefined) return;
|
||||
const journal = game.journal.entries.find(p=>p.name == name);
|
||||
if (journal == undefined) return;
|
||||
|
||||
let ringColor = "#000000";
|
||||
|
||||
let ringOffColor = settings.offRing;
|
||||
if (ringOffColor == undefined) ringOffColor = '#000000';
|
||||
|
||||
let ringOnColor = settings.onRing;
|
||||
if (ringOnColor == undefined) ringOnColor = '#00FF00';
|
||||
|
||||
|
||||
|
||||
if (journal.sheet.rendered) ringColor = ringOnColor;
|
||||
else ringColor = ringOffColor;
|
||||
|
||||
if (settings.displayCompendiumName) streamDeck.setTitle(name,context);
|
||||
streamDeck.setIcon(0,context,"",background,2,ringColor);
|
||||
}
|
||||
|
||||
keyPressJournal(settings){
|
||||
let name = settings.compendiumName;
|
||||
if (name == undefined) return;
|
||||
|
||||
const journal = game.journal.entries.find(p=>p.name == name);
|
||||
if (journal == undefined) return;
|
||||
//if (journal.sheet.rendered) journal.close();
|
||||
journal.render(true);
|
||||
}
|
||||
}
|
||||
126
src/playlist.js
@@ -3,11 +3,13 @@ import {streamDeck} from "../MaterialDeck.js";
|
||||
|
||||
export class PlaylistControl{
|
||||
constructor(){
|
||||
this.active = false;
|
||||
this.playlistOffset = 0;
|
||||
this.trackOffset = 0;
|
||||
}
|
||||
|
||||
async updateAll(){
|
||||
if (this.active == false) return;
|
||||
for (let i=0; i<32; i++){
|
||||
let data = streamDeck.buttonContext[i];
|
||||
if (data == undefined || data.action != 'playlist') continue;
|
||||
@@ -16,6 +18,7 @@ export class PlaylistControl{
|
||||
}
|
||||
|
||||
update(settings,context){
|
||||
this.active = true;
|
||||
if (settings.playlistMode == undefined) settings.playlistMode = 0;
|
||||
if (settings.playlistMode == 0){
|
||||
this.updatePlaylist(settings,context);
|
||||
@@ -31,8 +34,17 @@ export class PlaylistControl{
|
||||
|
||||
updatePlaylist(settings,context){
|
||||
let name = "";
|
||||
let src = 'action/images/Black.png';
|
||||
let background = '#000000';
|
||||
|
||||
let background = settings.background;
|
||||
if(background == undefined) background = '#000000';
|
||||
|
||||
let ringColor = "#000000"
|
||||
|
||||
let ringOffColor = settings.offRing;
|
||||
if (ringOffColor == undefined) ringOffColor = '#FF0000';
|
||||
|
||||
let ringOnColor = settings.onRing;
|
||||
if (ringOnColor == undefined) ringOnColor = '#00FF00';
|
||||
|
||||
let playlistType = settings.playlistType;
|
||||
if (playlistType == undefined) playlistType = 0;
|
||||
@@ -44,47 +56,39 @@ export class PlaylistControl{
|
||||
playlistNr--;
|
||||
playlistNr += this.playlistOffset;
|
||||
|
||||
let playBackground = settings.playBackground;
|
||||
if (playBackground == undefined) playBackground == '#00FF00';
|
||||
let stopBackground = settings.stopBackground;
|
||||
if (stopBackground == undefined) stopBackground == '#FF0000';
|
||||
|
||||
let playlist = this.getPlaylist(playlistNr);
|
||||
if (playlist != undefined){
|
||||
if (playlist.playing) {
|
||||
background = playBackground;
|
||||
src = 'action/images/playlist/stop.png';
|
||||
}
|
||||
else {
|
||||
background = stopBackground;
|
||||
src = 'action/images/playlist/play.png';
|
||||
}
|
||||
if (playlist.playing)
|
||||
ringColor = ringOnColor;
|
||||
else
|
||||
ringColor = ringOffColor;
|
||||
if (settings.displayName)
|
||||
name = playlist.name;
|
||||
}
|
||||
|
||||
}
|
||||
//Offset
|
||||
else {
|
||||
src = "";
|
||||
let onBackground = settings.onBackground;
|
||||
if (onBackground == undefined) onBackground = '#00FF00';
|
||||
let offBackground = settings.offBackground;
|
||||
if (offBackground == undefined) offBackground = '#000000';
|
||||
|
||||
let playlistOffset = parseInt(settings.offset);
|
||||
if (isNaN(playlistOffset)) playlistOffset = 0;
|
||||
if (playlistOffset == this.playlistOffset) background = onBackground;
|
||||
else background = offBackground;
|
||||
if (playlistOffset == this.playlistOffset) ringColor = ringOnColor;
|
||||
}
|
||||
streamDeck.setIcon(0,context,src,background);
|
||||
streamDeck.setIcon(0,context,"",background,2,ringColor);
|
||||
streamDeck.setTitle(name,context);
|
||||
}
|
||||
|
||||
updateTrack(settings,context){
|
||||
let name = "";
|
||||
let src = 'action/images/Black.png';
|
||||
let background = '#000000';
|
||||
|
||||
let background = settings.background;
|
||||
if(background == undefined) background = '#000000';
|
||||
|
||||
let ringColor = "#000000"
|
||||
|
||||
let ringOffColor = settings.offRing;
|
||||
if (ringOffColor == undefined) ringOffColor = '#FF0000';
|
||||
|
||||
let ringOnColor = settings.onRing;
|
||||
if (ringOnColor == undefined) ringOnColor = '#00FF00';
|
||||
|
||||
let playlistType = settings.playlistType;
|
||||
if (playlistType == undefined) playlistType = 0;
|
||||
@@ -100,52 +104,50 @@ export class PlaylistControl{
|
||||
trackNr--;
|
||||
trackNr += this.trackOffset;
|
||||
|
||||
let playBackground = settings.playBackground;
|
||||
if (playBackground == undefined) playBackground == '#00FF00';
|
||||
let stopBackground = settings.stopBackground;
|
||||
if (stopBackground == undefined) stopBackground == '#FF0000';
|
||||
|
||||
let playlist = this.getPlaylist(playlistNr);
|
||||
if (playlist != undefined){
|
||||
let track = playlist.data.sounds[trackNr];
|
||||
if (track != undefined){
|
||||
if (track.playing) {
|
||||
background = playBackground;
|
||||
src = 'action/images/playlist/stop.png';
|
||||
}
|
||||
else {
|
||||
background = stopBackground;
|
||||
src = 'action/images/playlist/play.png';
|
||||
}
|
||||
if (track.playing)
|
||||
ringColor = ringOnColor;
|
||||
else
|
||||
ringColor = ringOffColor;
|
||||
if (settings.displayName)
|
||||
name = track.name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//Offset
|
||||
else {
|
||||
src = "";
|
||||
let onBackground = settings.onBackground;
|
||||
if (onBackground == undefined) onBackground = '#00FF00';
|
||||
let offBackground = settings.offBackground;
|
||||
if (offBackground == undefined) offBackground = '#000000';
|
||||
|
||||
let trackOffset = parseInt(settings.offset);
|
||||
if (isNaN(trackOffset)) trackOffset = 0;
|
||||
if (trackOffset == this.trackOffset) background = onBackground;
|
||||
else background = offBackground;
|
||||
if (trackOffset == this.trackOffset) ringColor = ringOnColor;
|
||||
}
|
||||
streamDeck.setIcon(0,context,src,background);
|
||||
streamDeck.setIcon(0,context,"",background,2,ringColor);
|
||||
streamDeck.setTitle(name,context);
|
||||
}
|
||||
|
||||
stopAll(){
|
||||
stopAll(force=false){
|
||||
if (force){
|
||||
let playing = game.playlists.playing;
|
||||
for (let i=0; i<playing.length; i++){
|
||||
playing[i].stopAll();
|
||||
}
|
||||
}
|
||||
else {
|
||||
let playing = game.playlists.playing;
|
||||
console.log(playing);
|
||||
let selectedPlaylists = game.settings.get(MODULE.moduleName,'selectedPlaylists');
|
||||
console.log(selectedPlaylists);
|
||||
for (let i=0; i<playing.length; i++){
|
||||
const playlistNr = selectedPlaylists.findIndex(p => p == playing[i]._id);
|
||||
const mode = game.settings.get(MODULE.moduleName,'selectedPlaylistMethod')[playlistNr];
|
||||
if (mode == 0) playing[i].stopAll();
|
||||
console.log(playlistNr,mode);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
getPlaylist(num){
|
||||
let playlistId = game.settings.get(MODULE.moduleName,'selectedPlaylists')[num];
|
||||
@@ -169,11 +171,11 @@ export class PlaylistControl{
|
||||
let playlist = this.getPlaylist(playlistNr);
|
||||
if (playlist != undefined){
|
||||
if (settings.playlistMode == 0)
|
||||
this.playPlaylist(playlist);
|
||||
this.playPlaylist(playlist,playlistNr);
|
||||
else {
|
||||
let track = playlist.data.sounds[trackNr];
|
||||
if (track != undefined){
|
||||
this.playTrack(track,playlist);
|
||||
this.playTrack(track,playlist,playlistNr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,30 +193,38 @@ export class PlaylistControl{
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.stopAll();
|
||||
this.stopAll(true);
|
||||
}
|
||||
}
|
||||
|
||||
async playPlaylist(playlist){
|
||||
async playPlaylist(playlist,playlistNr){
|
||||
if (playlist.playing) {
|
||||
playlist.stopAll();
|
||||
return;
|
||||
}
|
||||
let mode = game.settings.get(MODULE.moduleName,'playlistMethod');
|
||||
let mode = game.settings.get(MODULE.moduleName,'selectedPlaylistMethod')[playlistNr];
|
||||
if (mode == 0) {
|
||||
mode = game.settings.get(MODULE.moduleName,'playlistMethod');
|
||||
if (mode == 2) await this.stopAll();
|
||||
}
|
||||
playlist.playAll();
|
||||
}
|
||||
|
||||
async playTrack(track,playlist){
|
||||
async playTrack(track,playlist,playlistNr){
|
||||
let play;
|
||||
if (track.playing)
|
||||
play = false;
|
||||
else {
|
||||
play = true;
|
||||
let mode = game.settings.get(MODULE.moduleName,'playlistMethod');
|
||||
let mode = game.settings.get(MODULE.moduleName,'selectedPlaylistMethod')[playlistNr];
|
||||
console.log('mode',mode);
|
||||
if (mode == 0) {
|
||||
mode = game.settings.get(MODULE.moduleName,'playlistMethod');
|
||||
if (mode == 1) await playlist.stopAll();
|
||||
else if (mode == 2) await this.stopAll();
|
||||
}
|
||||
else if (mode == 2) await playlist.stopAll();
|
||||
}
|
||||
await playlist.updateEmbeddedEntity("PlaylistSound", {_id: track._id, playing: play});
|
||||
playlist.update({playing: play});
|
||||
}
|
||||
|
||||
@@ -9,21 +9,34 @@ export const registerSettings = function() {
|
||||
//Enabled the module
|
||||
game.settings.register(MODULE.moduleName,'Enable', {
|
||||
name: "MaterialDeck.Sett.Enable",
|
||||
scope: "world",
|
||||
scope: "global",
|
||||
config: true,
|
||||
default: true,
|
||||
default: false,
|
||||
type: Boolean,
|
||||
onChange: x => window.location.reload()
|
||||
});
|
||||
|
||||
game.settings.register(MODULE.moduleName,'streamDeckModel', {
|
||||
name: "Stream Deck Model",
|
||||
hint: "Reduces the amount of macros and sounds in the macro and soundboard configuration screens. Gives a better overview, but if desired it can be set to XL to get the maximum number. This doesn't influence the operation of the module.",
|
||||
name: "MaterialDeck.Sett.Model",
|
||||
hint: "MaterialDeck.Sett.Model_Hint",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type:Number,
|
||||
default:1,
|
||||
choices:["Mini","Normal or Mobile","XL"],
|
||||
choices:["MaterialDeck.Sett.Model_Mini","MaterialDeck.Sett.Model_Normal","MaterialDeck.Sett.Model_XL"],
|
||||
});
|
||||
|
||||
/**
|
||||
* Sets the ip address of the server
|
||||
*/
|
||||
game.settings.register(MODULE.moduleName,'address', {
|
||||
name: "MaterialDeck.Sett.ServerAddr",
|
||||
hint: "MaterialDeck.Sett.ServerAddrHint",
|
||||
scope: "world",
|
||||
config: true,
|
||||
default: "localhost:3001",
|
||||
type: String,
|
||||
onChange: x => window.location.reload()
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -35,12 +48,12 @@ export const registerSettings = function() {
|
||||
config: false,
|
||||
type:Number,
|
||||
default:0,
|
||||
choices:["Default","One track per playlist","One track in total"],
|
||||
choices:["MaterialDeck.Playlist.Playmethod.Unrestricted","MaterialDeck.Playlist.Playmethod.OneTrackPlaylist","MaterialDeck.Playlist.Playmethod.OneTrackTotal"],
|
||||
});
|
||||
|
||||
game.settings.registerMenu(MODULE.moduleName, 'playlistConfigMenu',{
|
||||
name: "Playlist Config",
|
||||
label: "Playlist Config",
|
||||
name: "MaterialDeck.Sett.PlaylistConfig",
|
||||
label: "MaterialDeck.Sett.PlaylistConfig",
|
||||
type: playlistConfigForm,
|
||||
restricted: true
|
||||
});
|
||||
@@ -49,7 +62,23 @@ export const registerSettings = function() {
|
||||
name: "selectedPlaylists",
|
||||
scope: "world",
|
||||
type: Object,
|
||||
default: {a: "None",b: "None",c: "none",d: "none",e: "none",f: "none",g: "none",h: "none",i: "none"},
|
||||
default: {},
|
||||
config: false
|
||||
});
|
||||
|
||||
game.settings.register(MODULE.moduleName, 'selectedPlaylistMethod', {
|
||||
name: "selectedPlaylistMethod",
|
||||
scope: "world",
|
||||
type: Object,
|
||||
default: {},
|
||||
config: false
|
||||
});
|
||||
|
||||
game.settings.register(MODULE.moduleName, 'numberOfPlaylists', {
|
||||
name: "numberOfPlaylists",
|
||||
scope: "world",
|
||||
type: Number,
|
||||
default: 9,
|
||||
config: false
|
||||
});
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import {streamDeck} from "../MaterialDeck.js";
|
||||
|
||||
export class SoundboardControl{
|
||||
constructor(){
|
||||
this.active = false;
|
||||
this.offset = 0;
|
||||
this.activeSounds = [];
|
||||
for (let i=0; i<64; i++)
|
||||
@@ -10,6 +11,7 @@ export class SoundboardControl{
|
||||
}
|
||||
|
||||
async updateAll(){
|
||||
if (this.active == false) return;
|
||||
for (let i=0; i<32; i++){
|
||||
let data = streamDeck.buttonContext[i];
|
||||
if (data == undefined || data.action != 'soundboard') continue;
|
||||
@@ -18,12 +20,17 @@ export class SoundboardControl{
|
||||
}
|
||||
|
||||
update(settings,context){
|
||||
this.active = true;
|
||||
let mode = settings.soundboardMode;
|
||||
if (mode == undefined) mode = 0;
|
||||
|
||||
let txt = "";
|
||||
let src = "";
|
||||
let background = "#000000";
|
||||
|
||||
let background = settings.background;
|
||||
if (background == undefined) background = '#000000';
|
||||
|
||||
let ringColor = "#000000"
|
||||
|
||||
if (mode == 0){ //play sound
|
||||
let soundNr = parseInt(settings.soundNr);
|
||||
@@ -33,37 +40,33 @@ export class SoundboardControl{
|
||||
|
||||
let soundboardSettings = game.settings.get(MODULE.moduleName, 'soundboardSettings');
|
||||
|
||||
let onColor = soundboardSettings.colorOn[soundNr];
|
||||
let offColor = soundboardSettings.colorOff[soundNr];
|
||||
if (this.activeSounds[soundNr]==false)
|
||||
ringColor = soundboardSettings.colorOff[soundNr];
|
||||
else
|
||||
ringColor = soundboardSettings.colorOn[soundNr];
|
||||
|
||||
background = onColor;
|
||||
let ring = 2;
|
||||
if (this.activeSounds[soundNr]==false) {
|
||||
background = offColor;
|
||||
ring = 1;
|
||||
}
|
||||
if (settings.displayName) txt = soundboardSettings.name[soundNr];
|
||||
if (settings.displayIcon) src = soundboardSettings.img[soundNr];
|
||||
streamDeck.setTitle(txt,context);
|
||||
streamDeck.setIcon(1,context,src,background,ring,background);
|
||||
streamDeck.setIcon(1,context,src,background,2,ringColor);
|
||||
}
|
||||
else if (mode == 1) { //Offset
|
||||
src = "";
|
||||
let onBackground = settings.onBackground;
|
||||
if (onBackground == undefined) onBackground = '#00FF00';
|
||||
let offBackground = settings.offBackground;
|
||||
if (offBackground == undefined) offBackground = '#000000';
|
||||
let ringOffColor = settings.offRing;
|
||||
if (ringOffColor == undefined) ringOffColor = '#000000';
|
||||
|
||||
let ringOnColor = settings.onRing;
|
||||
if (ringOnColor == undefined) ringOnColor = '#00FF00';
|
||||
|
||||
let offset = parseInt(settings.offset);
|
||||
if (isNaN(offset)) offset = 0;
|
||||
if (offset == this.offset) background = onBackground;
|
||||
else background = offBackground;
|
||||
if (offset == this.offset) ringColor = ringOnColor;
|
||||
else ringColor = ringOffColor;
|
||||
streamDeck.setTitle(txt,context);
|
||||
streamDeck.setIcon(1,context,src,background);
|
||||
streamDeck.setIcon(1,context,"",background,2,ringColor);
|
||||
}
|
||||
else if (mode == 2) { //Stop all sounds
|
||||
let src = 'action/images/soundboard/stop.png';
|
||||
streamDeck.setIcon(0,context,src,settings.background);
|
||||
streamDeck.setIcon(0,context,src,background);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,30 +117,46 @@ export class SoundboardControl{
|
||||
this.playSound(soundNr,false,false);
|
||||
}
|
||||
|
||||
playSound(soundNr,repeat,play){
|
||||
let trackId = game.settings.get(MODULE.moduleName,'soundboardSettings').sounds[soundNr];
|
||||
async playSound(soundNr,repeat,play){
|
||||
const soundBoardSettings = game.settings.get(MODULE.moduleName,'soundboardSettings');
|
||||
const playlistId = soundBoardSettings.selectedPlaylists[soundNr];
|
||||
let src;
|
||||
if (playlistId == "" || playlistId == undefined) return;
|
||||
if (playlistId == 'none') return;
|
||||
else if (playlistId == 'FP') {
|
||||
src = soundBoardSettings.src[soundNr];
|
||||
const ret = await FilePicker.browse("data", src, {wildcard:true});
|
||||
const files = ret.files;
|
||||
if (files.length == 1) src = files;
|
||||
else {
|
||||
let value = Math.floor(Math.random() * Math.floor(files.length));
|
||||
src = files[value];
|
||||
}
|
||||
}
|
||||
else {
|
||||
const soundId = soundBoardSettings.sounds[soundNr];
|
||||
const sounds = game.playlists.entities.find(p => p._id == playlistId).data.sounds;
|
||||
if (sounds == undefined) return;
|
||||
const sound = sounds.find(p => p._id == soundId);
|
||||
if (sound == undefined) return;
|
||||
src = sound.path;
|
||||
}
|
||||
|
||||
let volume = game.settings.get(MODULE.moduleName,'soundboardSettings').volume[soundNr]/100;
|
||||
volume = AudioHelper.inputToVolume(volume);
|
||||
if (trackId == "" || trackId == undefined) return;
|
||||
|
||||
let payload = {
|
||||
"msgType": "playSound",
|
||||
"trackNr": soundNr,
|
||||
"src": src,
|
||||
"repeat": repeat,
|
||||
"play": play,
|
||||
"volume": volume
|
||||
};
|
||||
game.socket.emit(`module.MaterialDeck`, payload);
|
||||
|
||||
if (play){
|
||||
let trackId = game.settings.get(MODULE.moduleName,'soundboardSettings').sounds[soundNr];
|
||||
let playlistId = game.settings.get(MODULE.moduleName,'soundboardSettings').playlist;
|
||||
let sounds = game.playlists.entities.find(p => p._id == playlistId).data.sounds;
|
||||
let sound = sounds.find(p => p._id == trackId);
|
||||
if (sound == undefined){
|
||||
this.activeSounds[soundNr] = false;
|
||||
return;
|
||||
}
|
||||
volume *= game.settings.get("core", "globalInterfaceVolume");
|
||||
let src = sound.path;
|
||||
|
||||
let howl = new Howl({src, volume, loop: repeat, onend: (id)=>{
|
||||
if (repeat == false){
|
||||
@@ -157,5 +176,6 @@ export class SoundboardControl{
|
||||
this.activeSounds[soundNr] = false;
|
||||
}
|
||||
this.updateAll();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,8 @@ export class StreamDeck{
|
||||
let canvasBox = document.createElement('div');
|
||||
canvasBox.id = 'sdCanvasBox';
|
||||
document.body.appendChild(canvasBox); // adds the canvas to the body element
|
||||
|
||||
this.syllableRegex = /[^aeiouy]*[aeiouy]+(?:[^aeiouy]*$|[^aeiouy](?=[^aeiouy]))?/gi;
|
||||
}
|
||||
|
||||
setScreen(action){
|
||||
@@ -42,20 +44,90 @@ export class StreamDeck{
|
||||
clearContext(action,coordinates = {column:0,row:0}){
|
||||
let num = coordinates.column + coordinates.row*8;
|
||||
this.buttonContext[num] = undefined;
|
||||
if (this.getActive(action) == false){
|
||||
if (action == 'token') MODULE.tokenControl.active = false;
|
||||
else if (action == 'macro') MODULE.macroControl.active = false;
|
||||
else if (action == 'combattracker') MODULE.combatTracker.active = false;
|
||||
else if (action == 'playlist') MODULE.playlistControl.active = false;
|
||||
else if (action == 'soundboard') MODULE.soundboard.active = false;
|
||||
else if (action == 'other') MODULE.otherControls.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
getActive(action){
|
||||
for (let i=0; i<this.buttonContext.length; i++){
|
||||
if (this.buttonContext[i] != undefined && this.buttonContext[i].action == action)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get syllables of a word. Taken from: https://stackoverflow.com/a/49407494
|
||||
*/
|
||||
syllabify(words) {
|
||||
return words.match(this.syllableRegex);
|
||||
}
|
||||
|
||||
formatTitle(txt){
|
||||
let txtArray = txt.split(" ");
|
||||
let txtNew = "";
|
||||
for (let i=0; i<txtArray.length; i++){
|
||||
let txtNewPart = txtArray[i];
|
||||
if (i<txtArray.length-1 && txtArray[i].length + txtArray[i+1].length < 8) {
|
||||
txtNewPart = txtArray[i] + " " + txtArray[i+1];
|
||||
i++;
|
||||
let txtArrayOriginal = txt.split("\n");
|
||||
let txtArray = [];
|
||||
let counter = 0;
|
||||
for (let i=0; i<txtArrayOriginal.length; i++){
|
||||
|
||||
let txtArrayTemp = txtArrayOriginal[i].split(" ");
|
||||
for (let j=0; j<txtArrayTemp.length; j++){
|
||||
txtArray[counter] = txtArrayTemp[j];
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
let txtNew = "";
|
||||
let newTxtArray = ['','','','','','','','','','','','','','','','','','','',''];
|
||||
counter = 0;
|
||||
for (let i=0; i<txtArray.length; i++){
|
||||
|
||||
let txtNewPart = txtArray[i];
|
||||
|
||||
if (txtNewPart != undefined && txtNewPart.length > 10){
|
||||
let syllables = this.syllabify(txtNewPart);
|
||||
|
||||
for (let j=0; j<syllables.length; j++){
|
||||
if (syllables.length == 0){
|
||||
newTxtArray[counter] = txtNewPart;
|
||||
counter++;
|
||||
}
|
||||
else if (syllables[j+1] == undefined){
|
||||
newTxtArray[counter] = syllables[j];
|
||||
counter++;
|
||||
}
|
||||
else if ((syllables[j].length+syllables[j+1].length) < 10){
|
||||
newTxtArray[counter] = syllables[j]+syllables[j+1];
|
||||
if (syllables.length-2 > j) newTxtArray[counter] += '-';
|
||||
counter++;
|
||||
j++;
|
||||
}
|
||||
else {
|
||||
newTxtArray[counter] = syllables[j];
|
||||
if (syllables.length > j) newTxtArray[counter] += '-';
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
newTxtArray[counter] = txtNewPart;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
for (let i=0; i<counter; i++){
|
||||
if (txtNew.length > 0)
|
||||
txtNew += "\n";
|
||||
txtNew += txtNewPart;
|
||||
if (i<counter-1 && newTxtArray[i].length + newTxtArray[i+1].length < 10) {
|
||||
txtNew += newTxtArray[i] + " " + newTxtArray[i+1];
|
||||
i++;
|
||||
}
|
||||
else
|
||||
txtNew += newTxtArray[i];
|
||||
}
|
||||
return txtNew;
|
||||
}
|
||||
@@ -72,6 +144,7 @@ export class StreamDeck{
|
||||
}
|
||||
}
|
||||
let msg = {
|
||||
target: "SD",
|
||||
event: 'setTitle',
|
||||
context: context,
|
||||
payload: {
|
||||
@@ -84,6 +157,7 @@ export class StreamDeck{
|
||||
|
||||
setColor(context,color = '#000000'){
|
||||
let msg = {
|
||||
target: "SD",
|
||||
event: 'setIcon',
|
||||
context: context,
|
||||
url: '',
|
||||
@@ -97,6 +171,7 @@ export class StreamDeck{
|
||||
//var image = "data:image/svg+xml;charset=utf8,<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --><svg version=\"1.1\" id=\"Capa_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" viewBox=\"0 0 288 288\" style=\"enable-background:new 0 0 288 288;\" xml:space=\"preserve\"> <style> .text { font-family: sans-serif; fill: red; font-size: 10em; } </style><g> <text x=\"0px\" y=\"100px\" class=\"text\">GPUUTILIZATION</text></g></svg>";
|
||||
|
||||
var json = {
|
||||
target: "SD",
|
||||
event: "setImage",
|
||||
context: context,
|
||||
payload: {
|
||||
@@ -107,7 +182,7 @@ export class StreamDeck{
|
||||
MODULE.sendWS(JSON.stringify(json));
|
||||
}
|
||||
|
||||
setIcon(iconLocation, context,src,background = '#000000',ring=0,ringColor = "#000000"){
|
||||
setIcon(iconLocation, context,src,background = '#000000',ring=0,ringColor = "#000000",overlay=false){
|
||||
for (let i=0; i<32; i++){
|
||||
if (this.buttonContext[i] == undefined) continue;
|
||||
if (this.buttonContext[i].context == context) {
|
||||
@@ -122,17 +197,20 @@ export class StreamDeck{
|
||||
}
|
||||
|
||||
let split = src.split('.');
|
||||
let format = split[1];
|
||||
split = src.split(' ');
|
||||
//filter out stuff from Tokenizer
|
||||
let format = split[split.length-1].split('?')[0];
|
||||
split = split[0].split(' ');
|
||||
if (split[0] == 'fas' || split[0] == 'far' || split[0] == 'fal' || split[0] == 'fad') format = 'icon';
|
||||
let msg = {
|
||||
target: "SD",
|
||||
event: 'setIcon',
|
||||
context: context,
|
||||
url: src,
|
||||
format: format,
|
||||
background: background,
|
||||
ring: ring,
|
||||
ringColor: ringColor
|
||||
ringColor: ringColor,
|
||||
overlay: overlay
|
||||
};
|
||||
if (iconLocation == 0){
|
||||
MODULE.sendWS(JSON.stringify(msg));
|
||||
@@ -143,6 +221,7 @@ export class StreamDeck{
|
||||
|
||||
setState(state,context,action){
|
||||
let msg = {
|
||||
target: "SD",
|
||||
event: 'setStateCustom',
|
||||
context: context,
|
||||
action: action,
|
||||
@@ -156,12 +235,13 @@ export class StreamDeck{
|
||||
if (action == 'playlistcontrol')
|
||||
profile = 'MaterialDeck-Playlist'
|
||||
var json = {
|
||||
"source": 1,
|
||||
"event": "switchToProfile",
|
||||
"context": this.pluginId,
|
||||
"device": device,
|
||||
"payload": {
|
||||
"profile": profile
|
||||
target: "SD",
|
||||
source: 1,
|
||||
event: "switchToProfile",
|
||||
context: this.pluginId,
|
||||
device: device,
|
||||
payload: {
|
||||
profile: profile
|
||||
}
|
||||
};
|
||||
MODULE.sendWS(JSON.stringify(json));
|
||||
@@ -179,7 +259,6 @@ export class StreamDeck{
|
||||
var content = window.getComputedStyle(
|
||||
elm, ':before'
|
||||
).getPropertyValue('content')
|
||||
//console.log(elm);
|
||||
document.body.removeChild(elm);
|
||||
return content;
|
||||
};
|
||||
@@ -187,7 +266,7 @@ export class StreamDeck{
|
||||
getImage(data){
|
||||
if (data == undefined)
|
||||
return;
|
||||
console.log('image',data)
|
||||
//console.log('image',data)
|
||||
const context = data.context;
|
||||
var url = data.url;
|
||||
const format = data.format;
|
||||
@@ -245,19 +324,22 @@ export class StreamDeck{
|
||||
var content = window.getComputedStyle(
|
||||
elm, ':before'
|
||||
).getPropertyValue('content')
|
||||
//console.log(content[1]);
|
||||
canvas.removeChild(elm);
|
||||
ctx.fillText(content[1], 35, 105);
|
||||
const iconMeasurement = ctx.measureText(content[1]);
|
||||
const horOffset = (144-iconMeasurement.width)/2;
|
||||
const vertOffset = 144-(iconMeasurement.actualBoundingBoxAscent-iconMeasurement.actualBoundingBoxDescent)/2;
|
||||
ctx.fillText(content[1], horOffset, vertOffset);
|
||||
}
|
||||
|
||||
if (format != 'jpg' && format != 'jpeg' && format != 'png' && format != 'webm' && format != 'webp' && format != 'gif' && format != 'svg') url = "modules/MaterialDeck/img/transparant.png";
|
||||
if (url == "") url = "modules/MaterialDeck/img/transparant.png"
|
||||
//console.log(url);
|
||||
let resImageURL = url;
|
||||
|
||||
let img = new Image();
|
||||
img.setAttribute('crossorigin', 'anonymous');
|
||||
img.onload = () => {
|
||||
if (format == 'color') ctx.filter = "opacity(0)";
|
||||
if (data.overlay) ctx.filter = "brightness(60%)";
|
||||
//ctx.filter = "brightness(0) saturate(100%) invert(38%) sepia(62%) saturate(2063%) hue-rotate(209deg) brightness(90%) contrast(95%)";
|
||||
var imageAspectRatio = img.width / img.height;
|
||||
var canvasAspectRatio = canvas.width / canvas.height;
|
||||
|
||||
163
src/token.js
@@ -3,10 +3,11 @@ import {streamDeck} from "../MaterialDeck.js";
|
||||
|
||||
export class TokenControl{
|
||||
constructor(){
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
async update(tokenId){
|
||||
console.log('tokenId',tokenId)
|
||||
if (this.active == false) return;
|
||||
for (let i=0; i<32; i++){
|
||||
let data = streamDeck.buttonContext[i];
|
||||
if (data == undefined || data.action != 'token') continue;
|
||||
@@ -15,7 +16,6 @@ export class TokenControl{
|
||||
}
|
||||
|
||||
pushData(tokenId,settings,context,ring=0,ringColor='#000000'){
|
||||
console.log('tk',tokenId,settings)
|
||||
let name = false;
|
||||
let icon = false;
|
||||
let type = 0;
|
||||
@@ -75,10 +75,99 @@ export class TokenControl{
|
||||
}
|
||||
initiative = attributes.init.total;
|
||||
}
|
||||
else return;
|
||||
else {
|
||||
//Other systems
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
if (settings.onClick == 4) { //toggle visibility
|
||||
ring = 1;
|
||||
if (token.data.hidden){
|
||||
ring = 2;
|
||||
ringColor = "#FF7B00";
|
||||
}
|
||||
if (icon == false) {
|
||||
iconSrc = window.CONFIG.controlIcons.visibility;
|
||||
streamDeck.setIcon(1,context,iconSrc,background,ring,ringColor,true);
|
||||
}
|
||||
}
|
||||
else if (settings.onClick == 5) { //toggle combat state
|
||||
ring = 1;
|
||||
if (token.inCombat){
|
||||
ring = 2;
|
||||
ringColor = "#FF7B00";
|
||||
}
|
||||
if (icon == false) {
|
||||
iconSrc = window.CONFIG.controlIcons.combat;
|
||||
streamDeck.setIcon(1,context,iconSrc,background,ring,ringColor,true);
|
||||
}
|
||||
}
|
||||
else if (settings.onClick == 6) { //target token
|
||||
ring = 1;
|
||||
if (token.isTargeted){
|
||||
ring = 2;
|
||||
ringColor = "#FF7B00";
|
||||
}
|
||||
if (icon == false) {
|
||||
iconSrc = "fas fa-bullseye";
|
||||
streamDeck.setIcon(1,context,iconSrc,background,ring,ringColor);
|
||||
}
|
||||
}
|
||||
else if (settings.onClick == 7) { //toggle condition
|
||||
ring = 1;
|
||||
let condition = settings.condition;
|
||||
if (condition == undefined) condition = 0;
|
||||
|
||||
if (condition == 0 && icon == false){
|
||||
iconSrc = window.CONFIG.controlIcons.effects;
|
||||
}
|
||||
else if (icon == false) {
|
||||
let effect = CONFIG.statusEffects.find(e => e.id === this.getStatusId(condition));
|
||||
iconSrc = effect.icon;
|
||||
let effects = token.actor.effects.entries;
|
||||
let active = effects.find(e => e.isTemporary === this.getStatusId(condition));
|
||||
if (active != undefined){
|
||||
ring = 2;
|
||||
ringColor = "#FF7B00";
|
||||
}
|
||||
}
|
||||
streamDeck.setIcon(1,context,iconSrc,background,ring,ringColor,true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
iconSrc += "";
|
||||
if (settings.onClick == 4) { //toggle visibility
|
||||
if (icon == false) {
|
||||
iconSrc = window.CONFIG.controlIcons.visibility;
|
||||
streamDeck.setIcon(1,context,iconSrc,background,1,'#000000',true);
|
||||
}
|
||||
}
|
||||
else if (settings.onClick == 5) { //toggle combat state
|
||||
if (icon == false) {
|
||||
iconSrc = window.CONFIG.controlIcons.combat;
|
||||
streamDeck.setIcon(1,context,iconSrc,background,1,'#000000',true);
|
||||
}
|
||||
}
|
||||
else if (settings.onClick == 6) { //target token
|
||||
if (icon == false) {
|
||||
iconSrc = "fas fa-bullseye";
|
||||
streamDeck.setIcon(1,context,iconSrc,background,1,'#000000');
|
||||
}
|
||||
}
|
||||
else if (settings.onClick == 7) { //toggle condition
|
||||
let condition = settings.condition;
|
||||
if (condition == undefined) condition = 0;
|
||||
|
||||
if (condition == 0 && icon == false){
|
||||
iconSrc = window.CONFIG.controlIcons.effects;
|
||||
}
|
||||
else if (icon == false) {
|
||||
iconSrc = CONFIG.statusEffects.find(e => e.id === this.getStatusId(condition)).icon;
|
||||
}
|
||||
streamDeck.setIcon(1,context,iconSrc,background,1,'#000000',true);
|
||||
}
|
||||
}
|
||||
if (icon) streamDeck.setIcon(1,context,iconSrc,background,ring,ringColor);
|
||||
|
||||
@@ -91,7 +180,7 @@ export class TokenControl{
|
||||
streamDeck.setTitle(txt,context);
|
||||
}
|
||||
|
||||
keyPress(settings){
|
||||
async keyPress(settings){
|
||||
if (MODULE.selectedTokenId == undefined) return;
|
||||
const tokenId = MODULE.selectedTokenId;
|
||||
|
||||
@@ -110,8 +199,72 @@ export class TokenControl{
|
||||
else if (onClick == 2){ //Open character sheet
|
||||
token.actor.sheet.render(true);
|
||||
}
|
||||
else { //Open token config
|
||||
else if (onClick == 3) { //Open token config
|
||||
token.sheet._render(true);
|
||||
}
|
||||
else if (onClick == 4) { //Toggle visibility
|
||||
token.toggleVisibility();
|
||||
}
|
||||
else if (onClick == 5) { //Toggle combat state
|
||||
token.toggleCombat();
|
||||
}
|
||||
else if (onClick == 6) { //Target token
|
||||
token.setTarget(!token.isTargeted,{releaseOthers:false});
|
||||
}
|
||||
else if (onClick == 7) { //Toggle condition
|
||||
let condition = settings.condition;
|
||||
if (condition == undefined) condition = 0;
|
||||
|
||||
if (condition == 0){
|
||||
const effects = token.actor.effects.entries;
|
||||
for (let i=0; i<effects.length; i++){
|
||||
const effect = CONFIG.statusEffects.find(e => e.icon === effects[i].data.icon);
|
||||
await token.toggleEffect(effect)
|
||||
}
|
||||
}
|
||||
else {
|
||||
const effect = CONFIG.statusEffects.find(e => e.id === this.getStatusId(condition));
|
||||
token.toggleEffect(effect);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
getStatusId(nr){
|
||||
let id;
|
||||
if (nr == 1) id = 'dead';
|
||||
else if (nr == 2) id = 'unconscious';
|
||||
else if (nr == 3) id = 'sleep';
|
||||
else if (nr == 4) id = 'stun';
|
||||
else if (nr == 5) id = 'prone';
|
||||
else if (nr == 6) id = 'restrain';
|
||||
else if (nr == 7) id = 'paralysis';
|
||||
else if (nr == 8) id = 'fly';
|
||||
else if (nr == 9) id = 'bind';
|
||||
else if (nr == 10) id = 'deaf';
|
||||
else if (nr == 11) id = 'silence';
|
||||
else if (nr == 12) id = 'fear';
|
||||
else if (nr == 13) id = 'burning';
|
||||
else if (nr == 14) id = 'frozen';
|
||||
else if (nr == 15) id = 'shock';
|
||||
else if (nr == 16) id = 'corrode';
|
||||
else if (nr == 17) id = 'bleeding';
|
||||
else if (nr == 18) id = 'disease';
|
||||
else if (nr == 19) id = 'poison';
|
||||
else if (nr == 20) id = 'radiation';
|
||||
else if (nr == 21) id = 'regen';
|
||||
else if (nr == 22) id = 'degen';
|
||||
else if (nr == 23) id = 'upgrade';
|
||||
else if (nr == 24) id = 'downgrade';
|
||||
else if (nr == 25) id = 'target';
|
||||
else if (nr == 26) id = 'eye';
|
||||
else if (nr == 27) id = 'curse';
|
||||
else if (nr == 28) id = 'bless';
|
||||
else if (nr == 29) id = 'fireShield';
|
||||
else if (nr == 30) id = 'coldShield';
|
||||
else if (nr == 31) id = 'magicShield';
|
||||
else if (nr == 32) id = 'holyShield';
|
||||
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
.boxed {
|
||||
border: 1px solid black ;
|
||||
border-radius: 5px ;
|
||||
width: 100px;
|
||||
max-width: 166px;
|
||||
height: {{height}}px;
|
||||
}
|
||||
</style>
|
||||
@@ -13,12 +13,12 @@
|
||||
{{#each this.dataThis}}
|
||||
<div class="boxed" style="padding: 5px; margin:2px">
|
||||
<div style="text-align:center;">
|
||||
{{localize "MaterialDeck.Macro.Macro"}} {{this.iteration}}
|
||||
{{localize "MaterialDeck.Macro"}} {{this.iteration}}
|
||||
</div>
|
||||
<div>
|
||||
<select name="macros" class="macros-select" default="" style="max-width:140px;">
|
||||
{{#select this.macro}}
|
||||
<option value="">{{localize "MaterialDeck.Playlist.None"}}</option>
|
||||
<option value="">{{localize "MaterialDeck.None"}}</option>
|
||||
{{#each macros}}
|
||||
<option value="{{this._id}}">{{this.name}}</option>
|
||||
{{/each}}
|
||||
@@ -26,12 +26,12 @@
|
||||
</select>
|
||||
</div>
|
||||
{{#if this.furnace}}
|
||||
<label>{{localize "MaterialDeck.Macro.FurnaceArgs"}}</label>
|
||||
<label>{{localize "MaterialDeck.FurnaceArgs"}}</label>
|
||||
<input type="text" name="args" value="{{this.args}}">
|
||||
{{/if}}
|
||||
|
||||
<div class="flex-container" style="display:flex;flex-direction:row;padding-top:10px">
|
||||
<label style="flex:1">{{localize "MaterialDeck.Macro.Background"}}</label>
|
||||
<label style="flex:1">{{localize "MaterialDeck.Background"}}</label>
|
||||
<input style="flex:1" type="color" name="colorPicker" data-dtype="String" value="{{this.color}}">
|
||||
</div>
|
||||
</div>
|
||||
@@ -39,7 +39,7 @@
|
||||
</div>
|
||||
{{/each}}
|
||||
<button type="submit" name="submit">
|
||||
<i class="far fa-save"></i> {{localize "MaterialDeck.Playlist.Save"}}
|
||||
<i class="far fa-save"></i> {{localize "MaterialDeck.Save"}}
|
||||
</button>
|
||||
|
||||
</form>
|
||||
@@ -1,36 +1,48 @@
|
||||
<form autocomplete="off" onsubmit="event.preventDefault()">
|
||||
<div >
|
||||
<h2>{{localize "MaterialDeck.Playlist.Playmethod.Header"}}</h2>
|
||||
<h2>{{localize "MaterialDeck.PL.Settings"}}</h2>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{{localize "MaterialDeck.Playlist.Playmethod.Label"}}</label>
|
||||
<label>{{localize "MaterialDeck.PL.Mode"}}</label>
|
||||
<select name="playMethod" class="playMethod" default="">
|
||||
{{#select playMethod}}
|
||||
<option value="0">{{localize "MaterialDeck.Playlist.Playmethod.Unrestricted"}}</option>
|
||||
<option value="1">{{localize "MaterialDeck.Playlist.Playmethod.OneTrackPlaylist"}}</option>
|
||||
<option value="2">{{localize "MaterialDeck.Playlist.Playmethod.OneTrackTotal"}}</option>
|
||||
<option value="0">{{localize "MaterialDeck.PL.Unrestricted"}}</option>
|
||||
<option value="1">{{localize "MaterialDeck.PL.OneTrackPlaylist"}}</option>
|
||||
<option value="2">{{localize "MaterialDeck.PL.OneTrackTotal"}}</option>
|
||||
{{/select}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>{{localize "MaterialDeck.PL.Nr"}}</label>
|
||||
<input type="number" id="numberOfPlaylists" name="plNum" min="0" max="127" value={{numberOfPlaylists}}>
|
||||
</div>
|
||||
<div>
|
||||
<h2>{{localize "MaterialDeck.Playlist.Playlists"}}</h2>
|
||||
<h2>{{localize "MaterialDeck.Playlists"}}</h2>
|
||||
</div>
|
||||
{{#each playlistData}}
|
||||
<div class="form-group">
|
||||
<label>{{localize "MaterialDeck.Playlist.Playlist"}} {{this.iteration}}</label>
|
||||
<label>{{localize "MaterialDeck.Playlist"}} {{this.iteration}}</label>
|
||||
<select name="selectedPlaylist" class="playlist-select" default="">
|
||||
{{#select this.playlist}}
|
||||
<option value="">{{localize "MaterialDeck.Playlist.None"}}</option>
|
||||
<option value="">{{localize "MaterialDeck.None"}}</option>
|
||||
{{#each this.playlists}}
|
||||
<option value="{{this._id}}">{{this.name}}</option>
|
||||
{{/each}}
|
||||
{{/select}}
|
||||
</select>
|
||||
|
||||
<select name="playlistMethod" class="playlistMethod" default="">
|
||||
{{#select this.playlistMethod}}
|
||||
<option value="0">{{localize "MaterialDeck.PL.Mode"}}</option>
|
||||
<option value="1">{{localize "MaterialDeck.PL.Unrestricted"}}</option>
|
||||
<option value="2">{{localize "MaterialDeck.PL.OneTrack"}}</option>
|
||||
{{/select}}
|
||||
</select>
|
||||
</div>
|
||||
{{/each}}
|
||||
|
||||
<button type="submit" name="submit">
|
||||
<i class="far fa-save"></i> {{localize "MaterialDeck.Playlist.Save"}}
|
||||
<i class="far fa-save"></i> {{localize "MaterialDeck.Save"}}
|
||||
</button>
|
||||
|
||||
</form>
|
||||
@@ -3,47 +3,57 @@
|
||||
.boxed {
|
||||
border: 1px solid black ;
|
||||
border-radius: 5px ;
|
||||
width: 100px;
|
||||
height: 255px;
|
||||
max-width: 166px;
|
||||
height: 300px;
|
||||
}
|
||||
</style>
|
||||
<div class="form-group">
|
||||
<label>{{localize "MaterialDeck.Playlist.Playlist"}} </label>
|
||||
<select name="playlist" class="playlist-select" default="" style="max-width:200px;">
|
||||
{{#select playlist}}
|
||||
<option value="">{{localize "MaterialDeck.Playlist.None"}}</option>
|
||||
{{#each playlists}}
|
||||
<option value="{{this._id}}">{{this.name}}</option>
|
||||
{{/each}}
|
||||
{{/select}}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{#each soundData}}
|
||||
<div class="form-group">
|
||||
{{#each this.dataThis}}
|
||||
<div class="boxed" style="padding: 5px; margin:2px">
|
||||
<div style="text-align:center;">
|
||||
{{localize "MaterialDeck.Soundboard.Sound"}} {{this.iteration}}
|
||||
{{localize "MaterialDeck.Sound"}} {{this.iteration}}
|
||||
</div>
|
||||
<div style="text-align:center;">
|
||||
{{localize "MaterialDeck.Name"}}
|
||||
</div>
|
||||
<input type="text" name="name" value="{{this.name}}">
|
||||
|
||||
<div style="text-align:center;">
|
||||
{{localize "MaterialDeck.Soundboard.Sound"}}
|
||||
{{localize "MaterialDeck.Playlist"}}
|
||||
</div>
|
||||
<div>
|
||||
<select name="playlist" class="playlist-select" default="" style="width:132px;" id="playlists{{this.iteration}}">
|
||||
{{#select this.selectedPlaylist}}
|
||||
{{#each playlists}}
|
||||
<option value="{{this.id}}">{{this.name}}</option>
|
||||
{{/each}}
|
||||
{{/select}}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="text-align:center;">
|
||||
{{localize "MaterialDeck.Sound"}}
|
||||
</div>
|
||||
<div class="form-fields" style={{this.styleSS}}>
|
||||
<select name="sounds" class="sounds-select" default="" style="width:132px;" id="soundSelect{{this.iteration}}">
|
||||
{{#select this.sound}}
|
||||
<option value="">{{localize "MaterialDeck.Playlist.None"}}</option>
|
||||
<option value="">{{localize "MaterialDeck.None"}}</option>
|
||||
{{#each sounds}}
|
||||
<option value="{{this._id}}">{{this.name}}</option>
|
||||
{{/each}}
|
||||
{{/select}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-fields" style={{this.styleFP}}>
|
||||
<button type="button" class="file-picker" data-type="audio" data-target="src{{this.iteration}}" title="Browse Files" tabindex="-1">
|
||||
<i class="fas fa-file-import fa-fw"></i>
|
||||
</button>
|
||||
<input class="image" type="text" name="src{{this.iteration}}" id="srcPath{{this.iteration}}" placeholder="path/audio.mp3" value={{this.srcPath}}>
|
||||
</div>
|
||||
<div style="text-align:center;">
|
||||
{{localize "MaterialDeck.Soundboard.Icon"}}
|
||||
{{localize "MaterialDeck.Icon"}}
|
||||
</div>
|
||||
<div class="form-fields">
|
||||
<button type="button" class="file-picker" data-type="image" data-target="img{{this.iteration}}" title="Browse Files" tabindex="-1">
|
||||
@@ -52,24 +62,24 @@
|
||||
<input class="image" type="text" name="img{{this.iteration}}" id="imgPath{{this.iteration}}" placeholder="path/image.png" value={{this.imgPath}}>
|
||||
</div>
|
||||
<div class="flex-container" style="display:flex;flex-direction:row;padding-top:5px">
|
||||
<label style="flex:1">{{localize "MaterialDeck.Soundboard.On"}} </label>
|
||||
<label style="flex:1">{{localize "MaterialDeck.On"}} </label>
|
||||
<input style="flex:1" type="color" id="colorOn{{this.iteration}}" name="colorOn" style="flex:4" data-dtype="String" value="{{this.colorOn}}">
|
||||
<label style="flex:1"> {{localize "MaterialDeck.Soundboard.Off"}} </label>
|
||||
<label style="flex:1"> {{localize "MaterialDeck.Off"}} </label>
|
||||
<input style="flex:1" type="color" id="colorOff{{this.iteration}}" name="colorOff" style="flex:4" data-dtype="String" value="{{this.colorOff}}">
|
||||
</div>
|
||||
|
||||
<div class="form-group options">
|
||||
<label>{{localize "MaterialDeck.Soundboard.Playback"}}</label>
|
||||
<label>{{localize "MaterialDeck.Playback"}}</label>
|
||||
<select name="mode" style="flex:1">
|
||||
{{#select this.mode}}
|
||||
<option value="0">{{localize "MaterialDeck.Soundboard.Once"}}</option>
|
||||
<option value="1">{{localize "MaterialDeck.Soundboard.Repeat"}}</option>
|
||||
<option value="2">{{localize "MaterialDeck.Soundboard.Hold"}}</option>
|
||||
<option value="0">{{localize "MaterialDeck.Once"}}</option>
|
||||
<option value="1">{{localize "MaterialDeck.Repeat"}}</option>
|
||||
<option value="2">{{localize "MaterialDeck.Hold"}}</option>
|
||||
{{/select}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group options">
|
||||
<label>{{localize "MaterialDeck.Soundboard.Volume"}}</label>
|
||||
<label>{{localize "MaterialDeck.Volume"}}</label>
|
||||
<input type="range" min="0" max="100" value={{this.volume}} class="slider" name="volume" id="volume{{this.iteration}}">
|
||||
</div>
|
||||
|
||||
@@ -78,7 +88,7 @@
|
||||
</div>
|
||||
{{/each}}
|
||||
<button type="submit" name="submit">
|
||||
<i class="far fa-save"></i> {{localize "MaterialDeck.Playlist.Save"}}
|
||||
<i class="far fa-save"></i> {{localize "MaterialDeck.Save"}}
|
||||
</button>
|
||||
|
||||
</form>
|
||||
BIN
wiki/img/.thumb/CombatTracker.png.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
wiki/img/.thumb/ControlButtons.png.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
wiki/img/.thumb/MacroConfig.png.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
wiki/img/.thumb/ModuleSettings.png.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
wiki/img/.thumb/PlaylistConfig.png.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
wiki/img/.thumb/PlaylistControl.png.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
wiki/img/.thumb/SoundboardConfig.png.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
wiki/img/.thumb/StreamDeckSoftware.png.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
wiki/img/.thumb/TokenControl.png.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
wiki/img/CombatTracker.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
wiki/img/ControlButtons.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
wiki/img/MacroConfig.png
Normal file
|
After Width: | Height: | Size: 481 KiB |
BIN
wiki/img/ModuleSettings.png
Normal file
|
After Width: | Height: | Size: 134 KiB |
BIN
wiki/img/PlaylistConfig.png
Normal file
|
After Width: | Height: | Size: 194 KiB |
BIN
wiki/img/PlaylistControl.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
wiki/img/SoundboardConfig.png
Normal file
|
After Width: | Height: | Size: 609 KiB |
BIN
wiki/img/StreamDeckSoftware.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
wiki/img/TokenControl.png
Normal file
|
After Width: | Height: | Size: 76 KiB |