14 Commits

Author SHA1 Message Date
CDeenen
d1c059df7d v0.8.5 2020-11-17 06:47:30 +01:00
CDeenen
92f4db9e73 added wiki images 2020-11-12 00:01:07 +01:00
CDeenen
11851bba1e added wiki images 2020-11-11 22:28:25 +01:00
CDeenen
3f7998934b added wiki images 2020-11-11 22:25:16 +01:00
CDeenen
4eea123fac added wiki images 2020-11-11 22:14:17 +01:00
CDeenen
3a447604c9 changelog update 2020-11-11 04:17:23 +01:00
CDeenen
c6d23df938 changelog update 2020-11-11 04:16:46 +01:00
CDeenen
32367c2ba2 changelog update 2020-11-11 04:15:51 +01:00
CDeenen
9e80ae6150 changelog update 2020-11-11 04:15:10 +01:00
CDeenen
ead6db5a48 v0.8.4 2020-11-11 04:10:36 +01:00
CDeenen
4d277dc5c5 v0.8.3 2020-11-10 04:29:44 +01:00
CDeenen
d0dfec4cde v0.8.3 2020-11-10 04:27:13 +01:00
CDeenen
4db55e754c readme update 2020-11-10 02:22:37 +01:00
CDeenen
32b47e9a41 manifest update 2020-11-10 01:58:54 +01:00
37 changed files with 626 additions and 282 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
MaterialDeck.zip

View File

@@ -11,10 +11,10 @@ export var streamDeck;
export var tokenControl; export var tokenControl;
var move; var move;
export var macroControl; export var macroControl;
var combatTracker; export var combatTracker;
var playlistControl; export var playlistControl;
var soundboard; export var soundboard;
var otherControls; export var otherControls;
export const moduleName = "MaterialDeck"; export const moduleName = "MaterialDeck";
export var selectedTokenId; export var selectedTokenId;
@@ -45,7 +45,7 @@ async function analyzeWSmessage(msg,passthrough = false){
if (enableModule == false) return; if (enableModule == false) return;
const data = JSON.parse(msg); const data = JSON.parse(msg);
if (data == undefined || data.payload == undefined) return; if (data == undefined || data.payload == undefined) return;
console.log(data); //console.log("Received",data);
const action = data.action; const action = data.action;
const event = data.event; const event = data.event;
const context = data.context; const context = data.context;
@@ -62,7 +62,7 @@ async function analyzeWSmessage(msg,passthrough = false){
streamDeck.setContext(action,context,coordinates,settings); streamDeck.setContext(action,context,coordinates,settings);
if (action == 'token'){ if (action == 'token'){
if (selectedTokenId != undefined) tokenControl.active = true;
tokenControl.update(selectedTokenId); tokenControl.update(selectedTokenId);
} }
else if (action == 'macro') else if (action == 'macro')
@@ -126,7 +126,7 @@ function startWebsocket() {
ws.onopen = function() { ws.onopen = function() {
WSconnected = true; WSconnected = true;
ui.notifications.info("Material Deck Connected: "+ip+':'+port); ui.notifications.info("Material Deck "+game.i18n.localize("MaterialDeck.Notifications.Connected") +": "+ip+':'+port);
wsOpen = true; wsOpen = true;
let msg = { let msg = {
type: "Foundry" type: "Foundry"
@@ -276,6 +276,7 @@ Hooks.on('renderHotbar', (hotbar)=>{
Hooks.on('renderCombatTracker',()=>{ Hooks.on('renderCombatTracker',()=>{
if (enableModule == false || ready == false) return; if (enableModule == false || ready == false) return;
combatTracker.updateAll(); combatTracker.updateAll();
tokenControl.update(selectedTokenId);
}); });
Hooks.on('renderPlaylistDirectory', (playlistDirectory)=>{ Hooks.on('renderPlaylistDirectory', (playlistDirectory)=>{
@@ -309,6 +310,11 @@ Hooks.on('renderSceneControls',()=>{
otherControls.updateAll(); otherControls.updateAll();
}); });
Hooks.on('targetToken',(user,token,targeted)=>{
if (enableModule == false || ready == false) return;
if (token.id == selectedTokenId) tokenControl.update(selectedTokenId);
});
Hooks.once('init', ()=>{ Hooks.once('init', ()=>{
//CONFIG.debug.hooks = true; //CONFIG.debug.hooks = true;
registerSettings(); //in ./src/settings.js registerSettings(); //in ./src/settings.js

View File

@@ -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/MaterialDeck_Server/releases">Server</a><br>
<br>
Module manifest: https://raw.githubusercontent.com/CDeenen/MaterialDeck/Master/module.json

View File

@@ -0,0 +1,47 @@
# Changelog Material Deck Module
### 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>
</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>

View File

@@ -1,39 +1,40 @@
{ {
"MaterialDeck.Notifications.Disconnected": "Disconnected from mdServer, attempting to reconnect", "MaterialDeck.Notifications.Disconnected": "Disconnected from mdServer, attempting to reconnect",
"MaterialDeck.Notifications.ConnectFail": "Can't connect to mdServer, retrying", "MaterialDeck.Notifications.ConnectFail": "Can't connect to mdServer, 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.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.Playlist.Clear": "Clear data", "MaterialDeck.PL.Unrestricted": "Unrestricted",
"MaterialDeck.Playlist.Playmethod.Header": "Play Method", "MaterialDeck.PL.OneTrackPlaylist": "One track per playlist",
"MaterialDeck.Playlist.Playmethod.Label": "Method", "MaterialDeck.PL.OneTrackTotal": "One track in total",
"MaterialDeck.Playlist.Playmethod.Unrestricted": "Unrestricted", "MaterialDeck.PL.Header": "Play Method",
"MaterialDeck.Playlist.Playmethod.OneTrackPlaylist": "One track per playlist", "MaterialDeck.PL.Label": "Method",
"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.Soundboard.Sound": "Sound", "MaterialDeck.Playlists": "Playlists",
"MaterialDeck.Soundboard.Icon": "Icon", "MaterialDeck.Playlist": "Playlist",
"MaterialDeck.Soundboard.Playback": "Playback", "MaterialDeck.FurnaceArgs": "Furnace arguments",
"MaterialDeck.Soundboard.Once": "Once", "MaterialDeck.Background": "Background",
"MaterialDeck.Soundboard.Repeat": "Repeat", "MaterialDeck.Macro": "Macro",
"MaterialDeck.Soundboard.Hold": "Hold", "MaterialDeck.Sound": "Sound",
"MaterialDeck.Soundboard.On": "On", "MaterialDeck.Icon": "Icon",
"MaterialDeck.Soundboard.Off": "Off", "MaterialDeck.Once": "Once",
"MaterialDeck.Repeat": "Repeat",
"MaterialDeck.Macro.Macro": "Macro", "MaterialDeck.Hold": "Hold",
"MaterialDeck.Macro.Background": "Background", "MaterialDeck.Playback": "Playback",
"MaterialDeck.Macro.FurnaceArgs": "Furnace arguments", "MaterialDeck.Volume": "Volume",
"MaterialDeck.On": "On",
"MaterialDeck.Name": "Name" "MaterialDeck.Off": "Off",
"MaterialDeck.Name": "Name",
"MaterialDeck.None": "None",
"MaterialDeck.Save": "Save"
} }

View File

@@ -2,7 +2,7 @@
"name": "MaterialDeck", "name": "MaterialDeck",
"title": "Material Deck", "title": "Material Deck",
"description": "", "description": "",
"version": "0.8.2", "version": "0.8.5",
"author": "CDeenen", "author": "CDeenen",
"esmodules": [ "esmodules": [
"./MaterialDeck.js" "./MaterialDeck.js"
@@ -18,6 +18,6 @@
} }
], ],
"url": "https://github.com/CDeenen/MaterialDeck", "url": "https://github.com/CDeenen/MaterialDeck",
"manifest": "https://raw.githubusercontent.com/CDeenen/MaterialDeck/master/module.json", "manifest": "https://raw.githubusercontent.com/CDeenen/MaterialDeck/Master/module.json",
"download": "https://github.com/CDeenen/MaterialDeck/archive/master.zip" "download": "https://github.com/CDeenen/MaterialDeck/archive/Master.zip"
} }

View File

@@ -3,11 +3,12 @@ import {streamDeck, tokenControl} from "../MaterialDeck.js";
export class CombatTracker{ export class CombatTracker{
constructor(){ constructor(){
this.active = false;
this.combatantLength = 0; this.combatantLength = 0;
} }
async updateAll(){ async updateAll(){
if (this.active == false) return;
for (let i=0; i<32; i++){ for (let i=0; i<32; i++){
let data = streamDeck.buttonContext[i]; let data = streamDeck.buttonContext[i];
if (data == undefined || data.action != 'combattracker') continue; if (data == undefined || data.action != 'combattracker') continue;
@@ -16,6 +17,7 @@ export class CombatTracker{
} }
update(settings,context){ update(settings,context){
this.active = true;
let ctFunction = settings.combatTrackerFunction; let ctFunction = settings.combatTrackerFunction;
if (ctFunction == undefined) ctFunction == 0; if (ctFunction == undefined) ctFunction == 0;

View File

@@ -3,10 +3,12 @@ import {streamDeck} from "../MaterialDeck.js";
export class MacroControl{ export class MacroControl{
constructor(){ constructor(){
this.active = false;
this.offset = 0; this.offset = 0;
} }
async updateAll(){ async updateAll(){
if (this.active == false) return;
for (let i=0; i<32; i++){ for (let i=0; i<32; i++){
let data = streamDeck.buttonContext[i]; let data = streamDeck.buttonContext[i];
if (data == undefined || data.action != 'macro') continue; if (data == undefined || data.action != 'macro') continue;
@@ -15,10 +17,15 @@ export class MacroControl{
} }
update(settings,context){ update(settings,context){
this.active = true;
let mode = settings.macroMode; let mode = settings.macroMode;
let displayName = settings.displayName; let displayName = settings.displayName;
let macroNumber = settings.macroNumber; let macroNumber = settings.macroNumber;
let background = settings.background; let background = settings.background;
let icon = false;
if (settings.displayIcon) icon = true;
let ringColor = "#000000";
let ring = 0;
if(macroNumber == undefined || isNaN(parseInt(macroNumber))){ if(macroNumber == undefined || isNaN(parseInt(macroNumber))){
macroNumber = 0; macroNumber = 0;
} }
@@ -51,15 +58,15 @@ export class MacroControl{
src += macro.img; src += macro.img;
} }
} }
if (icon) streamDeck.setIcon(1,context,src,background);
streamDeck.setIcon(1,context,src,background); else streamDeck.setIcon(0, context, "", background);
if (displayName == 0) name = ""; if (displayName == 0) name = "";
streamDeck.setTitle(name,context); streamDeck.setTitle(name,context);
} }
else { else { //Macro board
let name = ""; let name = "";
let src = ''; let src = '';
if (settings.macroBoardMode == 0) { if (settings.macroBoardMode == 0) { //Execute macro
macroNumber += this.offset - 1; macroNumber += this.offset - 1;
if (macroNumber < 0) macroNumber = 0; if (macroNumber < 0) macroNumber = 0;
var macroId = game.settings.get(MODULE.moduleName,'macroSettings').macros[macroNumber]; var macroId = game.settings.get(MODULE.moduleName,'macroSettings').macros[macroNumber];
@@ -75,19 +82,23 @@ export class MacroControl{
} }
} }
} }
else { else { //Offset
src = ""; let ringOffColor = settings.offRing;
let onBackground = settings.onBackground; if (ringOffColor == undefined) ringOffColor = '#000000';
if (onBackground == undefined) onBackground = '#00FF00';
let offBackground = settings.offBackground; let ringOnColor = settings.onRing;
if (offBackground == undefined) offBackground = '#000000'; if (ringOnColor == undefined) ringOnColor = '#00FF00';
let macroOffset = parseInt(settings.macroOffset); let macroOffset = parseInt(settings.macroOffset);
if (macroOffset == undefined || isNaN(macroOffset)) macroOffset = 0; if (macroOffset == undefined || isNaN(macroOffset)) macroOffset = 0;
if (macroOffset == parseInt(this.offset)) background = onBackground; if (macroOffset == parseInt(this.offset)) ringColor = ringOnColor;
else background = offBackground; 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 = ""; if (displayName == 0) name = "";
streamDeck.setTitle(name,context); streamDeck.setTitle(name,context);
} }
@@ -140,13 +151,13 @@ export class MacroControl{
let mode = settings.macroMode; let mode = settings.macroMode;
if (mode == undefined) mode = 0; if (mode == undefined) mode = 0;
if (mode == 0 || mode == 1){
let macroNumber = settings.macroNumber; let macroNumber = settings.macroNumber;
if(macroNumber == undefined || isNaN(parseInt(macroNumber))){ if(macroNumber == undefined || isNaN(parseInt(macroNumber))){
macroNumber = 0; macroNumber = 0;
} }
if (mode == 0 || mode == 1)
this.executeHotbar(macroNumber,mode); this.executeHotbar(macroNumber,mode);
}
else { else {
if (settings.macroBoardMode == 0) if (settings.macroBoardMode == 0)
this.executeBoard(macroNumber); this.executeBoard(macroNumber);

View File

@@ -13,7 +13,7 @@ export class playlistConfigForm extends FormApplication {
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
id: "playlist-config", id: "playlist-config",
title: "Material Deck: Playlist Config", title: "Material Deck: "+game.i18n.localize("MaterialDeck.Sett.PlaylistConfig"),
template: "./modules/MaterialDeck/templates/playlistConfig.html", template: "./modules/MaterialDeck/templates/playlistConfig.html",
classes: ["sheet"], classes: ["sheet"],
width: 500 width: 500

View File

@@ -2,22 +2,37 @@ import * as MODULE from "../MaterialDeck.js";
export class Move{ export class Move{
constructor(){ constructor(){
this.active = false;
} }
keyPress(settings){ keyPress(settings){
console.log('move',settings)
let dir = settings.dir; let dir = settings.dir;
let mode = settings.mode; let mode = settings.mode;
if (mode == undefined) mode = 0; if (mode == undefined) mode = 0;
if (dir == undefined) dir = 0; if (dir == undefined) dir = 0;
if (dir < 9){
if (settings.mode == '1') if (settings.mode == '1')
this.moveToken(MODULE.selectedTokenId,dir); this.moveToken(MODULE.selectedTokenId,dir);
else else
this.moveCanvas(dir); 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){ async moveToken(tokenId,dir){
if (tokenId == undefined) return; if (tokenId == undefined) return;
const token = canvas.tokens.children[0].children.find(p => p.id == tokenId); const token = canvas.tokens.children[0].children.find(p => p.id == tokenId);
const gridSize = canvas.scene.data.grid; const gridSize = canvas.scene.data.grid;
let x = token.x; let x = token.x;

View File

@@ -3,10 +3,12 @@ import {streamDeck} from "../MaterialDeck.js";
export class OtherControls{ export class OtherControls{
constructor(){ constructor(){
this.active = false;
this.offset = 0; this.offset = 0;
} }
async updateAll(){ async updateAll(){
if (this.active == false) return;
for (let i=0; i<32; i++){ for (let i=0; i<32; i++){
let data = streamDeck.buttonContext[i]; let data = streamDeck.buttonContext[i];
if (data == undefined || data.action != 'other') continue; if (data == undefined || data.action != 'other') continue;
@@ -15,6 +17,7 @@ export class OtherControls{
} }
update(settings,context){ update(settings,context){
this.active = true;
let mode = settings.otherMode; let mode = settings.otherMode;
if (mode == undefined) mode = 0; if (mode == undefined) mode = 0;
@@ -59,25 +62,39 @@ export class OtherControls{
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
updatePause(pauseFunction,context){ updatePause(pauseFunction,context){
if (pauseFunction == undefined) pauseFunction = 0;
let src = ""; let src = "";
let name = ""; if (pauseFunction == undefined) pauseFunction = 0;
let background = "#000000";
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 (pauseFunction == 0){ //Pause game
if (game.paused) background = "#00FF00" if (game.paused) ringColor = ringOnColor;
else ringColor = ringOffColor;
src = 'action/images/other/pause/pause.png'; src = 'action/images/other/pause/pause.png';
} }
else if (pauseFunction == 1){ //Resume game 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'; src = 'action/images/other/pause/resume.png';
} }
else if (pauseFunction == 2) { //toggle 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'; src = 'action/images/other/pause/playpause.png';
} }
streamDeck.setIcon(0,context,src,background); streamDeck.setIcon(0,context,src,background,2,ringColor);
streamDeck.setTitle(name,context);
} }
keyPressPause(pauseFunction){ keyPressPause(pauseFunction){
@@ -101,56 +118,54 @@ export class OtherControls{
let func = settings.sceneFunction; let func = settings.sceneFunction;
if (func == undefined) func = 0; 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 if (func == 0){ //visible scenes
let nr = parseInt(settings.sceneNr); let nr = parseInt(settings.sceneNr);
if (isNaN(nr)) nr = 1; if (isNaN(nr)) nr = 1;
nr--; nr--;
let background = settings.background;
if (background == undefined) background = "#000000";
let scene = game.scenes.apps[0].scenes[nr]; let scene = game.scenes.apps[0].scenes[nr];
let name = "";
let src = "";
let ringColor = "#000000";
let ring = 1;
if (scene != undefined){ if (scene != undefined){
if (scene.isView) { if (scene.isView)
ringColor = "#00FF00"; ringColor = ringOnColor;
ring = 2; else
} ringColor = ringOffColor;
if (settings.displaySceneName) name = scene.name; if (settings.displaySceneName) name = scene.name;
if (settings.displaySceneIcon) src = scene.img; if (settings.displaySceneIcon) src = scene.img;
if (scene.active) name += "\n(Active)"; if (scene.active) name += "\n(Active)";
} }
streamDeck.setTitle(name,context);
streamDeck.setIcon(1, context,src,background,ring,ringColor);
} }
else if (func == 1) { //all scenes 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); let scene = game.scenes.apps[1].entities.find(p=>p.data.name == name);
name = "";
if (scene != undefined){ if (scene != undefined){
if (scene.isView) { if (scene.isView)
ringColor = "#00FF00"; ringColor = ringOnColor;
ring = 2; else
} ringColor = ringOffColor;
if (settings.displaySceneName) name = scene.name; if (settings.displaySceneName) name = scene.name;
if (settings.displaySceneIcon) src = scene.img; if (settings.displaySceneIcon) src = scene.img;
if (scene.active) name += "\n(Active)"; 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){ keyPressScene(settings){
@@ -177,9 +192,9 @@ export class OtherControls{
scene.view(); scene.view();
} }
} }
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
updateControl(settings,context){ updateControl(settings,context){
@@ -189,54 +204,68 @@ export class OtherControls{
let tool = settings.tool; let tool = settings.tool;
if (tool == undefined) tool = 0; if (tool == undefined) tool = 0;
let background = settings.background;
if (background == undefined) background = '#000000';
let ringColor = '#000000'
const controlName = this.getControlName(control); const controlName = this.getControlName(control);
const toolName = this.getToolName(control,tool); const toolName = this.getToolName(control,tool);
let txt = ""; let txt = "";
let src = ""; let src = "";
let background = "#000000"; const activeControl = ui.controls.activeControl;
let ringColor = "#FF7B00" const activeTool = ui.controls.activeTool;
let selectedControl;
let selectedTool;
let ring = 1;
let activeControl = ui.controls.activeControl;
let activeTool = ui.controls.activeTool;
if (control == 0){ if (control == 0) { //displayed controls
let controlNr = parseInt(settings.controlNr); let controlNr = parseInt(settings.controlNr);
if (isNaN(controlNr)) controlNr = 1; if (isNaN(controlNr)) controlNr = 1;
controlNr--; controlNr--;
selectedControl = ui.controls.controls.find(c => c.name == ui.controls.activeControl); const selectedControl = ui.controls.controls[controlNr];
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);
if (selectedControl != undefined){ if (selectedControl != undefined){
if (tool == 0){ //open category if (tool == 0){ //open category
txt = game.i18n.localize(selectedControl.title); txt = game.i18n.localize(selectedControl.title);
src = selectedControl.icon; src = selectedControl.icon;
if (activeControl == selectedControl.name) 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 { else {
selectedTool = selectedControl.tools.find(t => t.name == toolName); const selectedTool = selectedControl.tools.find(t => t.name == toolName);
if (selectedTool != undefined){ if (selectedTool != undefined){
txt = game.i18n.localize(selectedTool.title); txt = game.i18n.localize(selectedTool.title);
src = selectedTool.icon; src = selectedTool.icon;
@@ -246,15 +275,14 @@ export class OtherControls{
ringColor = "#A600FF" ringColor = "#A600FF"
else else
ringColor = "#340057" ringColor = "#340057"
ring = 2;
} }
else if (activeTool == selectedTool.name && activeControl == selectedControl.name) 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); streamDeck.setTitle(txt,context);
} }
@@ -268,29 +296,39 @@ export class OtherControls{
const controlName = this.getControlName(control); const controlName = this.getControlName(control);
const toolName = this.getToolName(control,tool); const toolName = this.getToolName(control,tool);
if (control == 0){ //displayed tools if (control == 0){ //displayed controls
let controlNr = parseInt(settings.controlNr); let controlNr = parseInt(settings.controlNr);
if (isNaN(controlNr)) controlNr = 1; if (isNaN(controlNr)) controlNr = 1;
controlNr--; controlNr--;
let selectedControl = ui.controls.controls.find(c => c.name == ui.controls.activeControl); const selectedControl = ui.controls.controls[controlNr];
if (selectedControl != undefined){ 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 != undefined){
if (selectedTool.toggle){ if (selectedTool.toggle) {
let newValue = !selectedTool.active; selectedTool.active = !selectedTool.active;
selectedTool.active = newValue; selectedTool.onClick(selectedTool.active);
} }
else if (selectedTool.button){ else if (selectedTool.button){
selectedTool.onClick(); selectedTool.onClick();
} }
else else
selectedControl.activeTool = selectedTool.name; selectedControl.activeTool = selectedTool.name;
ui.controls.render();
} }
} }
} }
else { //select control 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 (selectedControl != undefined){
if (tool == 0){ //open category if (tool == 0){ //open category
ui.controls.activeControl = controlName; ui.controls.activeControl = controlName;
@@ -298,13 +336,13 @@ export class OtherControls{
canvas.getLayer(selectedControl.layer).activate(); canvas.getLayer(selectedControl.layer).activate();
} }
else { else {
let selectedTool = selectedControl.tools.find(t => t.name == toolName); const selectedTool = selectedControl.tools.find(t => t.name == toolName);
if (selectedTool != undefined){ if (selectedTool != undefined){
ui.controls.activeControl = controlName; ui.controls.activeControl = controlName;
canvas.getLayer(selectedControl.layer).activate(); canvas.getLayer(selectedControl.layer).activate();
if (selectedTool.toggle){ if (selectedTool.toggle) {
let newValue = !selectedTool.active; selectedTool.active = !selectedTool.active;
selectedTool.active = newValue; selectedTool.onClick(selectedTool.active);
} }
else if (selectedTool.button){ else if (selectedTool.button){
selectedTool.onClick(); selectedTool.onClick();
@@ -313,21 +351,13 @@ export class OtherControls{
selectedControl.activeTool = toolName; selectedControl.activeTool = toolName;
} }
} }
}
}
ui.controls.render(); 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){ getControlName(control){
control--; control -= 2;
let name; let name;
if (control == 0) name = 'token'; if (control == 0) name = 'token';
else if (control == 1) name = 'measure'; else if (control == 1) name = 'measure';
@@ -341,7 +371,7 @@ export class OtherControls{
} }
getToolName(control,tool){ getToolName(control,tool){
control--; control -= 2;
tool--; tool--;
let name; let name;
if (control == 0){ //basic controls if (control == 0){ //basic controls

View File

@@ -3,11 +3,13 @@ import {streamDeck} from "../MaterialDeck.js";
export class PlaylistControl{ export class PlaylistControl{
constructor(){ constructor(){
this.active = false;
this.playlistOffset = 0; this.playlistOffset = 0;
this.trackOffset = 0; this.trackOffset = 0;
} }
async updateAll(){ async updateAll(){
if (this.active == false) return;
for (let i=0; i<32; i++){ for (let i=0; i<32; i++){
let data = streamDeck.buttonContext[i]; let data = streamDeck.buttonContext[i];
if (data == undefined || data.action != 'playlist') continue; if (data == undefined || data.action != 'playlist') continue;
@@ -16,6 +18,7 @@ export class PlaylistControl{
} }
update(settings,context){ update(settings,context){
this.active = true;
if (settings.playlistMode == undefined) settings.playlistMode = 0; if (settings.playlistMode == undefined) settings.playlistMode = 0;
if (settings.playlistMode == 0){ if (settings.playlistMode == 0){
this.updatePlaylist(settings,context); this.updatePlaylist(settings,context);
@@ -31,8 +34,17 @@ export class PlaylistControl{
updatePlaylist(settings,context){ updatePlaylist(settings,context){
let name = ""; 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; let playlistType = settings.playlistType;
if (playlistType == undefined) playlistType = 0; if (playlistType == undefined) playlistType = 0;
@@ -44,47 +56,39 @@ export class PlaylistControl{
playlistNr--; playlistNr--;
playlistNr += this.playlistOffset; 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); let playlist = this.getPlaylist(playlistNr);
if (playlist != undefined){ if (playlist != undefined){
if (playlist.playing) { if (playlist.playing)
background = playBackground; ringColor = ringOnColor;
src = 'action/images/playlist/stop.png'; else
} ringColor = ringOffColor;
else {
background = stopBackground;
src = 'action/images/playlist/play.png';
}
if (settings.displayName) if (settings.displayName)
name = playlist.name; name = playlist.name;
} }
} }
//Offset //Offset
else { 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); let playlistOffset = parseInt(settings.offset);
if (isNaN(playlistOffset)) playlistOffset = 0; if (isNaN(playlistOffset)) playlistOffset = 0;
if (playlistOffset == this.playlistOffset) background = onBackground; if (playlistOffset == this.playlistOffset) ringColor = ringOnColor;
else background = offBackground;
} }
streamDeck.setIcon(0,context,src,background); streamDeck.setIcon(0,context,"",background,2,ringColor);
streamDeck.setTitle(name,context); streamDeck.setTitle(name,context);
} }
updateTrack(settings,context){ updateTrack(settings,context){
let name = ""; 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; let playlistType = settings.playlistType;
if (playlistType == undefined) playlistType = 0; if (playlistType == undefined) playlistType = 0;
@@ -100,43 +104,26 @@ export class PlaylistControl{
trackNr--; trackNr--;
trackNr += this.trackOffset; 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); let playlist = this.getPlaylist(playlistNr);
if (playlist != undefined){ if (playlist != undefined){
let track = playlist.data.sounds[trackNr]; let track = playlist.data.sounds[trackNr];
if (track != undefined){ if (track != undefined){
if (track.playing) { if (track.playing)
background = playBackground; ringColor = ringOnColor;
src = 'action/images/playlist/stop.png'; else
} ringColor = ringOffColor;
else {
background = stopBackground;
src = 'action/images/playlist/play.png';
}
if (settings.displayName) if (settings.displayName)
name = track.name; name = track.name;
} }
} }
} }
//Offset //Offset
else { 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); let trackOffset = parseInt(settings.offset);
if (isNaN(trackOffset)) trackOffset = 0; if (isNaN(trackOffset)) trackOffset = 0;
if (trackOffset == this.trackOffset) background = onBackground; if (trackOffset == this.trackOffset) ringColor = ringOnColor;
else background = offBackground;
} }
streamDeck.setIcon(0,context,src,background); streamDeck.setIcon(0,context,"",background,2,ringColor);
streamDeck.setTitle(name,context); streamDeck.setTitle(name,context);
} }

View File

@@ -17,13 +17,13 @@ export const registerSettings = function() {
}); });
game.settings.register(MODULE.moduleName,'streamDeckModel', { game.settings.register(MODULE.moduleName,'streamDeckModel', {
name: "Stream Deck Model", name: "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.", hint: "MaterialDeck.Sett.Model_Hint",
scope: "world", scope: "world",
config: true, config: true,
type:Number, type:Number,
default:1, default:1,
choices:["Mini","Normal or Mobile","XL"], choices:["MaterialDeck.Sett.Model_Mini","MaterialDeck.Sett.Model_Normal","MaterialDeck.Sett.Model_XL"],
}); });
/** /**
@@ -35,12 +35,12 @@ export const registerSettings = function() {
config: false, config: false,
type:Number, type:Number,
default:0, 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',{ game.settings.registerMenu(MODULE.moduleName, 'playlistConfigMenu',{
name: "Playlist Config", name: "MaterialDeck.Sett.PlaylistConfig",
label: "Playlist Config", label: "MaterialDeck.Sett.PlaylistConfig",
type: playlistConfigForm, type: playlistConfigForm,
restricted: true restricted: true
}); });

View File

@@ -3,6 +3,7 @@ import {streamDeck} from "../MaterialDeck.js";
export class SoundboardControl{ export class SoundboardControl{
constructor(){ constructor(){
this.active = false;
this.offset = 0; this.offset = 0;
this.activeSounds = []; this.activeSounds = [];
for (let i=0; i<64; i++) for (let i=0; i<64; i++)
@@ -10,6 +11,7 @@ export class SoundboardControl{
} }
async updateAll(){ async updateAll(){
if (this.active == false) return;
for (let i=0; i<32; i++){ for (let i=0; i<32; i++){
let data = streamDeck.buttonContext[i]; let data = streamDeck.buttonContext[i];
if (data == undefined || data.action != 'soundboard') continue; if (data == undefined || data.action != 'soundboard') continue;
@@ -18,12 +20,17 @@ export class SoundboardControl{
} }
update(settings,context){ update(settings,context){
this.active = true;
let mode = settings.soundboardMode; let mode = settings.soundboardMode;
if (mode == undefined) mode = 0; if (mode == undefined) mode = 0;
let txt = ""; let txt = "";
let src = ""; let src = "";
let background = "#000000";
let background = settings.background;
if (background == undefined) background = '#000000';
let ringColor = "#000000"
if (mode == 0){ //play sound if (mode == 0){ //play sound
let soundNr = parseInt(settings.soundNr); let soundNr = parseInt(settings.soundNr);
@@ -33,37 +40,33 @@ export class SoundboardControl{
let soundboardSettings = game.settings.get(MODULE.moduleName, 'soundboardSettings'); let soundboardSettings = game.settings.get(MODULE.moduleName, 'soundboardSettings');
let onColor = soundboardSettings.colorOn[soundNr]; if (this.activeSounds[soundNr]==false)
let offColor = soundboardSettings.colorOff[soundNr]; 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.displayName) txt = soundboardSettings.name[soundNr];
if (settings.displayIcon) src = soundboardSettings.img[soundNr]; if (settings.displayIcon) src = soundboardSettings.img[soundNr];
streamDeck.setTitle(txt,context); 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 else if (mode == 1) { //Offset
src = ""; let ringOffColor = settings.offRing;
let onBackground = settings.onBackground; if (ringOffColor == undefined) ringOffColor = '#000000';
if (onBackground == undefined) onBackground = '#00FF00';
let offBackground = settings.offBackground; let ringOnColor = settings.onRing;
if (offBackground == undefined) offBackground = '#000000'; if (ringOnColor == undefined) ringOnColor = '#00FF00';
let offset = parseInt(settings.offset); let offset = parseInt(settings.offset);
if (isNaN(offset)) offset = 0; if (isNaN(offset)) offset = 0;
if (offset == this.offset) background = onBackground; if (offset == this.offset) ringColor = ringOnColor;
else background = offBackground; else ringColor = ringOffColor;
streamDeck.setTitle(txt,context); streamDeck.setTitle(txt,context);
streamDeck.setIcon(1,context,src,background); streamDeck.setIcon(1,context,"",background,2,ringColor);
} }
else if (mode == 2) { //Stop all sounds else if (mode == 2) { //Stop all sounds
let src = 'action/images/soundboard/stop.png'; let src = 'action/images/soundboard/stop.png';
streamDeck.setIcon(0,context,src,settings.background); streamDeck.setIcon(0,context,src,background);
} }
} }

View File

@@ -23,6 +23,8 @@ export class StreamDeck{
let canvasBox = document.createElement('div'); let canvasBox = document.createElement('div');
canvasBox.id = 'sdCanvasBox'; canvasBox.id = 'sdCanvasBox';
document.body.appendChild(canvasBox); // adds the canvas to the body element document.body.appendChild(canvasBox); // adds the canvas to the body element
this.syllableRegex = /[^aeiouy]*[aeiouy]+(?:[^aeiouy]*$|[^aeiouy](?=[^aeiouy]))?/gi;
} }
setScreen(action){ setScreen(action){
@@ -42,20 +44,90 @@ export class StreamDeck{
clearContext(action,coordinates = {column:0,row:0}){ clearContext(action,coordinates = {column:0,row:0}){
let num = coordinates.column + coordinates.row*8; let num = coordinates.column + coordinates.row*8;
this.buttonContext[num] = undefined; 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){ formatTitle(txt){
let txtArray = txt.split(" "); let txtArrayOriginal = txt.split("\n");
let txtNew = ""; let txtArray = [];
for (let i=0; i<txtArray.length; i++){ let counter = 0;
let txtNewPart = txtArray[i]; for (let i=0; i<txtArrayOriginal.length; i++){
if (i<txtArray.length-1 && txtArray[i].length + txtArray[i+1].length < 8) {
txtNewPart = txtArray[i] + " " + txtArray[i+1]; let txtArrayTemp = txtArrayOriginal[i].split(" ");
i++; 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) if (txtNew.length > 0)
txtNew += "\n"; 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; return txtNew;
} }
@@ -107,7 +179,7 @@ export class StreamDeck{
MODULE.sendWS(JSON.stringify(json)); 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++){ for (let i=0; i<32; i++){
if (this.buttonContext[i] == undefined) continue; if (this.buttonContext[i] == undefined) continue;
if (this.buttonContext[i].context == context) { if (this.buttonContext[i].context == context) {
@@ -122,8 +194,9 @@ export class StreamDeck{
} }
let split = src.split('.'); let split = src.split('.');
let format = split[1]; //filter out stuff from Tokenizer
split = src.split(' '); 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'; if (split[0] == 'fas' || split[0] == 'far' || split[0] == 'fal' || split[0] == 'fad') format = 'icon';
let msg = { let msg = {
event: 'setIcon', event: 'setIcon',
@@ -132,7 +205,8 @@ export class StreamDeck{
format: format, format: format,
background: background, background: background,
ring: ring, ring: ring,
ringColor: ringColor ringColor: ringColor,
overlay: overlay
}; };
if (iconLocation == 0){ if (iconLocation == 0){
MODULE.sendWS(JSON.stringify(msg)); MODULE.sendWS(JSON.stringify(msg));
@@ -179,7 +253,6 @@ export class StreamDeck{
var content = window.getComputedStyle( var content = window.getComputedStyle(
elm, ':before' elm, ':before'
).getPropertyValue('content') ).getPropertyValue('content')
//console.log(elm);
document.body.removeChild(elm); document.body.removeChild(elm);
return content; return content;
}; };
@@ -187,7 +260,7 @@ export class StreamDeck{
getImage(data){ getImage(data){
if (data == undefined) if (data == undefined)
return; return;
console.log('image',data) //console.log('image',data)
const context = data.context; const context = data.context;
var url = data.url; var url = data.url;
const format = data.format; const format = data.format;
@@ -245,19 +318,22 @@ export class StreamDeck{
var content = window.getComputedStyle( var content = window.getComputedStyle(
elm, ':before' elm, ':before'
).getPropertyValue('content') ).getPropertyValue('content')
//console.log(content[1]);
canvas.removeChild(elm); 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 (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" if (url == "") url = "modules/MaterialDeck/img/transparant.png"
//console.log(url);
let resImageURL = url; let resImageURL = url;
let img = new Image(); let img = new Image();
img.setAttribute('crossorigin', 'anonymous');
img.onload = () => { img.onload = () => {
if (format == 'color') ctx.filter = "opacity(0)"; 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%)"; //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 imageAspectRatio = img.width / img.height;
var canvasAspectRatio = canvas.width / canvas.height; var canvasAspectRatio = canvas.width / canvas.height;

View File

@@ -3,10 +3,11 @@ import {streamDeck} from "../MaterialDeck.js";
export class TokenControl{ export class TokenControl{
constructor(){ constructor(){
this.active = false;
} }
async update(tokenId){ async update(tokenId){
console.log('tokenId',tokenId) if (this.active == false) return;
for (let i=0; i<32; i++){ for (let i=0; i<32; i++){
let data = streamDeck.buttonContext[i]; let data = streamDeck.buttonContext[i];
if (data == undefined || data.action != 'token') continue; if (data == undefined || data.action != 'token') continue;
@@ -15,7 +16,6 @@ export class TokenControl{
} }
pushData(tokenId,settings,context,ring=0,ringColor='#000000'){ pushData(tokenId,settings,context,ring=0,ringColor='#000000'){
console.log('tk',tokenId,settings)
let name = false; let name = false;
let icon = false; let icon = false;
let type = 0; let type = 0;
@@ -75,10 +75,99 @@ export class TokenControl{
} }
initiative = attributes.init.total; 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 { else {
iconSrc += ""; 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); if (icon) streamDeck.setIcon(1,context,iconSrc,background,ring,ringColor);
@@ -91,7 +180,7 @@ export class TokenControl{
streamDeck.setTitle(txt,context); streamDeck.setTitle(txt,context);
} }
keyPress(settings){ async keyPress(settings){
if (MODULE.selectedTokenId == undefined) return; if (MODULE.selectedTokenId == undefined) return;
const tokenId = MODULE.selectedTokenId; const tokenId = MODULE.selectedTokenId;
@@ -110,8 +199,72 @@ export class TokenControl{
else if (onClick == 2){ //Open character sheet else if (onClick == 2){ //Open character sheet
token.actor.sheet.render(true); token.actor.sheet.render(true);
} }
else { //Open token config else if (onClick == 3) { //Open token config
token.sheet._render(true); 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;
} }
} }

View File

@@ -13,12 +13,12 @@
{{#each this.dataThis}} {{#each this.dataThis}}
<div class="boxed" style="padding: 5px; margin:2px"> <div class="boxed" style="padding: 5px; margin:2px">
<div style="text-align:center;"> <div style="text-align:center;">
{{localize "MaterialDeck.Macro.Macro"}} {{this.iteration}} {{localize "MaterialDeck.Macro"}} {{this.iteration}}
</div> </div>
<div> <div>
<select name="macros" class="macros-select" default="" style="max-width:140px;"> <select name="macros" class="macros-select" default="" style="max-width:140px;">
{{#select this.macro}} {{#select this.macro}}
<option value="">{{localize "MaterialDeck.Playlist.None"}}</option> <option value="">{{localize "MaterialDeck.None"}}</option>
{{#each macros}} {{#each macros}}
<option value="{{this._id}}">{{this.name}}</option> <option value="{{this._id}}">{{this.name}}</option>
{{/each}} {{/each}}
@@ -26,12 +26,12 @@
</select> </select>
</div> </div>
{{#if this.furnace}} {{#if this.furnace}}
<label>{{localize "MaterialDeck.Macro.FurnaceArgs"}}</label> <label>{{localize "MaterialDeck.FurnaceArgs"}}</label>
<input type="text" name="args" value="{{this.args}}"> <input type="text" name="args" value="{{this.args}}">
{{/if}} {{/if}}
<div class="flex-container" style="display:flex;flex-direction:row;padding-top:10px"> <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}}"> <input style="flex:1" type="color" name="colorPicker" data-dtype="String" value="{{this.color}}">
</div> </div>
</div> </div>
@@ -39,7 +39,7 @@
</div> </div>
{{/each}} {{/each}}
<button type="submit" name="submit"> <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> </button>
</form> </form>

View File

@@ -1,26 +1,26 @@
<form autocomplete="off" onsubmit="event.preventDefault()"> <form autocomplete="off" onsubmit="event.preventDefault()">
<div > <div >
<h2>{{localize "MaterialDeck.Playlist.Playmethod.Header"}}</h2> <h2>{{localize "MaterialDeck.PL.Header"}}</h2>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{{localize "MaterialDeck.Playlist.Playmethod.Label"}}</label> <label>{{localize "MaterialDeck.PL.Label"}}</label>
<select name="playMethod" class="playMethod" default=""> <select name="playMethod" class="playMethod" default="">
{{#select playMethod}} {{#select playMethod}}
<option value="0">{{localize "MaterialDeck.Playlist.Playmethod.Unrestricted"}}</option> <option value="0">{{localize "MaterialDeck.PL.Unrestricted"}}</option>
<option value="1">{{localize "MaterialDeck.Playlist.Playmethod.OneTrackPlaylist"}}</option> <option value="1">{{localize "MaterialDeck.PL.OneTrackPlaylist"}}</option>
<option value="2">{{localize "MaterialDeck.Playlist.Playmethod.OneTrackTotal"}}</option> <option value="2">{{localize "MaterialDeck.PL.OneTrackTotal"}}</option>
{{/select}} {{/select}}
</select> </select>
</div> </div>
<div> <div>
<h2>{{localize "MaterialDeck.Playlist.Playlists"}}</h2> <h2>{{localize "MaterialDeck.Playlists"}}</h2>
</div> </div>
{{#each playlistData}} {{#each playlistData}}
<div class="form-group"> <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 name="selectedPlaylist" class="playlist-select" default="">
{{#select this.playlist}} {{#select this.playlist}}
<option value="">{{localize "MaterialDeck.Playlist.None"}}</option> <option value="">{{localize "MaterialDeck.None"}}</option>
{{#each this.playlists}} {{#each this.playlists}}
<option value="{{this._id}}">{{this.name}}</option> <option value="{{this._id}}">{{this.name}}</option>
{{/each}} {{/each}}
@@ -30,7 +30,7 @@
{{/each}} {{/each}}
<button type="submit" name="submit"> <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> </button>
</form> </form>

View File

@@ -8,10 +8,10 @@
} }
</style> </style>
<div class="form-group"> <div class="form-group">
<label>{{localize "MaterialDeck.Playlist.Playlist"}}&nbsp;&nbsp;&nbsp;</label> <label>{{localize "MaterialDeck.Playlist"}}&nbsp;&nbsp;&nbsp;</label>
<select name="playlist" class="playlist-select" default="" style="max-width:200px;"> <select name="playlist" class="playlist-select" default="" style="max-width:200px;">
{{#select playlist}} {{#select playlist}}
<option value="">{{localize "MaterialDeck.Playlist.None"}}</option> <option value="">{{localize "MaterialDeck.None"}}</option>
{{#each playlists}} {{#each playlists}}
<option value="{{this._id}}">{{this.name}}</option> <option value="{{this._id}}">{{this.name}}</option>
{{/each}} {{/each}}
@@ -23,19 +23,19 @@
{{#each this.dataThis}} {{#each this.dataThis}}
<div class="boxed" style="padding: 5px; margin:2px"> <div class="boxed" style="padding: 5px; margin:2px">
<div style="text-align:center;"> <div style="text-align:center;">
{{localize "MaterialDeck.Soundboard.Sound"}} {{this.iteration}} {{localize "MaterialDeck.Sound"}} {{this.iteration}}
</div> </div>
<div style="text-align:center;"> <div style="text-align:center;">
{{localize "MaterialDeck.Name"}} {{localize "MaterialDeck.Name"}}
</div> </div>
<input type="text" name="name" value="{{this.name}}"> <input type="text" name="name" value="{{this.name}}">
<div style="text-align:center;"> <div style="text-align:center;">
{{localize "MaterialDeck.Soundboard.Sound"}} {{localize "MaterialDeck.Sound"}}
</div> </div>
<div> <div>
<select name="sounds" class="sounds-select" default="" style="width:132px;" id="soundSelect{{this.iteration}}"> <select name="sounds" class="sounds-select" default="" style="width:132px;" id="soundSelect{{this.iteration}}">
{{#select this.sound}} {{#select this.sound}}
<option value="">{{localize "MaterialDeck.Playlist.None"}}</option> <option value="">{{localize "MaterialDeck.None"}}</option>
{{#each sounds}} {{#each sounds}}
<option value="{{this._id}}">{{this.name}}</option> <option value="{{this._id}}">{{this.name}}</option>
{{/each}} {{/each}}
@@ -43,7 +43,7 @@
</select> </select>
</div> </div>
<div style="text-align:center;"> <div style="text-align:center;">
{{localize "MaterialDeck.Soundboard.Icon"}} {{localize "MaterialDeck.Icon"}}
</div> </div>
<div class="form-fields"> <div class="form-fields">
<button type="button" class="file-picker" data-type="image" data-target="img{{this.iteration}}" title="Browse Files" tabindex="-1"> <button type="button" class="file-picker" data-type="image" data-target="img{{this.iteration}}" title="Browse Files" tabindex="-1">
@@ -52,24 +52,24 @@
<input class="image" type="text" name="img{{this.iteration}}" id="imgPath{{this.iteration}}" placeholder="path/image.png" value={{this.imgPath}}> <input class="image" type="text" name="img{{this.iteration}}" id="imgPath{{this.iteration}}" placeholder="path/image.png" value={{this.imgPath}}>
</div> </div>
<div class="flex-container" style="display:flex;flex-direction:row;padding-top:5px"> <div class="flex-container" style="display:flex;flex-direction:row;padding-top:5px">
<label style="flex:1">{{localize "MaterialDeck.Soundboard.On"}}&nbsp;&nbsp;&nbsp;</label> <label style="flex:1">{{localize "MaterialDeck.On"}}&nbsp;&nbsp;&nbsp;</label>
<input style="flex:1" type="color" id="colorOn{{this.iteration}}" name="colorOn" style="flex:4" data-dtype="String" value="{{this.colorOn}}"> <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">&nbsp;{{localize "MaterialDeck.Soundboard.Off"}}&nbsp;&nbsp;</label> <label style="flex:1">&nbsp;{{localize "MaterialDeck.Off"}}&nbsp;&nbsp;</label>
<input style="flex:1" type="color" id="colorOff{{this.iteration}}" name="colorOff" style="flex:4" data-dtype="String" value="{{this.colorOff}}"> <input style="flex:1" type="color" id="colorOff{{this.iteration}}" name="colorOff" style="flex:4" data-dtype="String" value="{{this.colorOff}}">
</div> </div>
<div class="form-group options"> <div class="form-group options">
<label>{{localize "MaterialDeck.Soundboard.Playback"}}</label> <label>{{localize "MaterialDeck.Playback"}}</label>
<select name="mode" style="flex:1"> <select name="mode" style="flex:1">
{{#select this.mode}} {{#select this.mode}}
<option value="0">{{localize "MaterialDeck.Soundboard.Once"}}</option> <option value="0">{{localize "MaterialDeck.Once"}}</option>
<option value="1">{{localize "MaterialDeck.Soundboard.Repeat"}}</option> <option value="1">{{localize "MaterialDeck.Repeat"}}</option>
<option value="2">{{localize "MaterialDeck.Soundboard.Hold"}}</option> <option value="2">{{localize "MaterialDeck.Hold"}}</option>
{{/select}} {{/select}}
</select> </select>
</div> </div>
<div class="form-group options"> <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}}"> <input type="range" min="0" max="100" value={{this.volume}} class="slider" name="volume" id="volume{{this.iteration}}">
</div> </div>
@@ -78,7 +78,7 @@
</div> </div>
{{/each}} {{/each}}
<button type="submit" name="submit"> <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> </button>
</form> </form>

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
wiki/img/CombatTracker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
wiki/img/ControlButtons.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
wiki/img/MacroConfig.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 KiB

BIN
wiki/img/ModuleSettings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

BIN
wiki/img/PlaylistConfig.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
wiki/img/TokenControl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB