diff --git a/web-ui/BMD-Camera-Control.js b/web-ui/BMD-Camera-Control.js index 2493558..33aabc7 100644 --- a/web-ui/BMD-Camera-Control.js +++ b/web-ui/BMD-Camera-Control.js @@ -19,9 +19,6 @@ class BMDCamera { // Current Transport Mode (string) transportMode; - - // Whether the transport is playing or not (boolean) - isPlaying; // Playback state (JSON object) playbackState; @@ -80,6 +77,9 @@ class BMDCamera { CCcolor; CClumacontribution; + // Keep track of unimplemented functions on the camera (array of strings) + UnimplementedFunctionality = []; + // ============= CONSTRUCTOR ================ constructor(hostname, index) { this.hostname = hostname; @@ -117,7 +117,6 @@ class BMDCamera { this.updateUISupportedCodecFormats(); this.updateUISupportedVideoFormats(); this.updateUITransportMode(); - this.updateUIisPlaying(); this.updateUIPlaybackState(); this.updateUIRecordState(); this.updateUITimecode(); @@ -133,14 +132,15 @@ class BMDCamera { this.updateUIshutter(); this.updateUIAutoExposureMode(); this.updateUIColorCorrection(); + this.updateUILinks(); } updateUIname() { - document.getElementsByClassName("cameraName")[this.index].innerHTML = this.name; + document.getElementById("cameraName").innerHTML = this.name; } updateUIhostname() { - //TBD + document.getElementById("hostnameInput").value = this.hostname; } updateUICodecFormat() { @@ -163,26 +163,25 @@ class BMDCamera { //TBD } - updateUIisPlaying() { - //TBD - } - updateUIPlaybackState() { //TBD } updateUIRecordState() { if (this.recordState.recording) { - document.getElementsByClassName("cameraControlsContainer")[this.index].classList.add("liveCam"); + document.getElementById("cameraControlHeadContainer").classList.add("liveCam"); + document.getElementById("cameraControlExpandedHeadContainer").classList.add("liveCam"); } else { - document.getElementsByClassName("cameraControlsContainer")[this.index].classList.remove("liveCam"); + document.getElementById("cameraControlHeadContainer").classList.remove("liveCam"); + document.getElementById("cameraControlExpandedHeadContainer").classList.remove("liveCam"); } } updateUITimecode() { + // Redo this to work with no leading 0 var tcString = parseInt(this.timecode.timecode.toString(16),10).toString().match(/.{1,2}/g).join(':'); - document.getElementsByClassName("timecodeLabel")[this.index].innerHTML = tcString; + document.getElementById("timecodeLabel").innerHTML = tcString; } updateUIPresets() { @@ -194,21 +193,21 @@ class BMDCamera { } updateUIAperture() { - document.getElementsByClassName("irisRange")[this.index].value = this.apertureNormalised; - document.getElementsByClassName("apertureStopsLabel")[this.index].innerHTML = this.apertureStop.toFixed(1); + document.getElementById("irisRange").value = this.apertureNormalised; + document.getElementById("apertureStopsLabel").innerHTML = this.apertureStop.toFixed(1); } updateUIZoom() { - document.getElementsByClassName("zoomRange")[this.index].value = this.zoomNormalised; - document.getElementsByClassName("zoomMMLabel")[this.index].innerHTML = this.zoomMM; + document.getElementById("zoomRange").value = this.zoomNormalised; + document.getElementById("zoomMMLabel").innerHTML = this.zoomMM; } updateUIFocus() { - document.getElementsByClassName("focusRange")[this.index].value = this.focusNormalised; + document.getElementById("focusRange").value = this.focusNormalised; } updateUIISO() { - // TBD + document.getElementById("ISOInput").value = this.ISO; } updateUIgain() { @@ -220,15 +219,15 @@ class BMDCamera { gainString = this.gain+"db" } - document.getElementsByClassName("gainSpan")[this.index].innerHTML = gainString; + document.getElementById("gainSpan").innerHTML = gainString; } updateUIWhiteBalance() { - document.getElementsByClassName("whiteBalanceSpan")[this.index].innerHTML = this.WhiteBalance+"K"; + document.getElementById("whiteBalanceSpan").innerHTML = this.WhiteBalance+"K"; } updateUINDStop() { - document.getElementsByClassName("ndFilterSpan")[this.index].innerHTML = this.NDStop; + document.getElementById("ndFilterSpan").innerHTML = this.NDStop; } updateUIshutter() { @@ -237,11 +236,15 @@ class BMDCamera { if ('shutterSpeed' in this.shutter) { shutterString = "1/"+this.shutter.shutterSpeed } else { - var shangleString = this.shutter.shutterAngle.toString(); - shutterString = shangleString.slice(0,3)+(shangleString.slice(3,4) == '0' ? '' : "."+shangleString.slice(3,4))+"°" + var shangleString = (this.shutter.shutterAngle / 100).toFixed(1).toString() + if (shangleString.indexOf(".0") > 0) { + shutterString = parseFloat(shangleString).toFixed(0)+"°"; + } else { + shutterString = shangleString+"°"; + } } - document.getElementsByClassName("shutterSpan")[this.index].innerHTML = shutterString; + document.getElementById("shutterSpan").innerHTML = shutterString; } updateUIAutoExposureMode() { @@ -249,7 +252,34 @@ class BMDCamera { } updateUIColorCorrection() { - //TBD + // Lift + document.getElementsByClassName("CClumaLabel")[0].innerHTML = this.CClift.luma.toFixed(2); + document.getElementsByClassName("CCredLabel")[0].innerHTML = this.CClift.red.toFixed(2); + document.getElementsByClassName("CCgreenLabel")[0].innerHTML = this.CClift.green.toFixed(2); + document.getElementsByClassName("CCblueLabel")[0].innerHTML = this.CClift.blue.toFixed(2); + + // Gamma + document.getElementsByClassName("CClumaLabel")[1].innerHTML = this.CCgamma.luma.toFixed(2); + document.getElementsByClassName("CCredLabel")[1].innerHTML = this.CCgamma.red.toFixed(2); + document.getElementsByClassName("CCgreenLabel")[1].innerHTML = this.CCgamma.green.toFixed(2); + document.getElementsByClassName("CCblueLabel")[1].innerHTML = this.CCgamma.blue.toFixed(2); + + // Gain + document.getElementsByClassName("CClumaLabel")[2].innerHTML = this.CCgain.luma.toFixed(2); + document.getElementsByClassName("CCredLabel")[2].innerHTML = this.CCgain.red.toFixed(2); + document.getElementsByClassName("CCgreenLabel")[2].innerHTML = this.CCgain.green.toFixed(2); + document.getElementsByClassName("CCblueLabel")[2].innerHTML = this.CCgain.blue.toFixed(2); + + // Offset + document.getElementsByClassName("CClumaLabel")[3].innerHTML = this.CCoffset.luma.toFixed(2); + document.getElementsByClassName("CCredLabel")[3].innerHTML = this.CCoffset.red.toFixed(2); + document.getElementsByClassName("CCgreenLabel")[3].innerHTML = this.CCoffset.green.toFixed(2); + document.getElementsByClassName("CCblueLabel")[3].innerHTML = this.CCoffset.blue.toFixed(2); + } + + updateUILinks() { + document.getElementById("documentationLink").href = "http://"+this.hostname+"/control/documentation.html"; + document.getElementById("mediaManagerLink").href = "http://"+this.hostname; } // =============== GETTERS ================== @@ -257,86 +287,82 @@ class BMDCamera { // name, hostname, APIaddress, index handled by constructor getCodecFormat() { - this.pullData("/system/codecFormat").then((value) => {this.codecFormat = value}); + this.pullData("/system/codecFormat").then((value) => {this.codecFormat = value; this.updateUICodecFormat()}); } getVideoFormat() { - this.pullData("/system/videoFormat").then((value) => {this.videoFormat = value}); + this.pullData("/system/videoFormat").then((value) => {this.videoFormat = value; this.updateUIVideoFormat()}); } getSupportedCodecFormats() { - this.pullData("/system/supportedCodecFormats").then((value) => {this.supportedCodecFormats = value}); + this.pullData("/system/supportedCodecFormats").then((value) => {this.supportedCodecFormats = value; this.updateUISupportedCodecFormats()}); } getSupportedVideoFormats() { - this.pullData("/system/supportedVideoFormats").then((value) => {this.supportedVideoFormats = value}); + this.pullData("/system/supportedVideoFormats").then((value) => {this.supportedVideoFormats = value; this.updateUISupportedVideoFormats()}); } getTransportMode() { - this.pullData("/transports/0").then((value) => {this.transportMode = value}); - } - - getIsPlaying() { - this.pullData("/transports/0/play").then((value) => {this.isPlaying = value}); + this.pullData("/transports/0").then((value) => {this.transportMode = value; this.updateUITransportMode()}); } getPlaybackState() { - this.pullData("/transports/0/playback").then((value) => {this.playbackState = value}); + this.pullData("/transports/0/playback").then((value) => {this.playbackState = value; this.updateUIPlaybackState()}); } getRecordState() { - this.pullData("/transports/0/record").then((value) => {this.recordState = value}); + this.pullData("/transports/0/record").then((value) => {this.recordState = value; this.updateUIRecordState()}); } getTimecode() { - this.pullData("/transports/0/timecode").then((value) => {this.timecode = value}); + this.pullData("/transports/0/timecode").then((value) => {this.timecode = value; this.updateUITimecode()}); this.pullData("/transports/0/timecode/source").then((value) => {this.timecode.source = value.source}); } getPresets() { - this.pullData("/presets").then((value) => {this.presets = value.presets}); + this.pullData("/presets").then((value) => {this.presets = value.presets; this.updateUIPresets()}); } getActivePreset() { - this.pullData("/presets/active").then((value) => {this.activePreset = value}); + this.pullData("/presets/active").then((value) => {this.activePreset = value; this.updateUIActivePreset()}); } getAperture() { - this.pullData("/lens/iris").then((value) => {this.apertureStop = value.apertureStop; this.apertureNormalised = value.normalised}); + this.pullData("/lens/iris").then((value) => {this.apertureStop = value.apertureStop; this.apertureNormalised = value.normalised; this.updateUIAperture()}); } getZoom() { - this.pullData("/lens/zoom").then((value) => {this.zoomMM = value.focalLength; this.zoomNormalised = value.normalised}); + this.pullData("/lens/zoom").then((value) => {this.zoomMM = value.focalLength; this.zoomNormalised = value.normalised; this.updateUIZoom()}); } getFocus() { - this.pullData("/lens/focus").then((value) => {this.focusNormalised = value.normalised}); + this.pullData("/lens/focus").then((value) => {this.focusNormalised = value.normalised; this.updateUIFocus()}); } getISO() { - this.pullData("/video/iso").then((value) => {this.ISO = value.iso}); + this.pullData("/video/iso").then((value) => {this.ISO = value.iso; this.updateUIISO()}); } getGain() { - this.pullData("/video/gain").then((value) => {this.gain = value.gain}); + this.pullData("/video/gain").then((value) => {this.gain = value.gain; this.updateUIgain()}); } getWhiteBalance() { this.pullData("/video/whiteBalance").then((value) => {this.WhiteBalance = value.whiteBalance}); - this.pullData("/video/whiteBalanceTint").then((value) => {this.WhiteBalanceTint = value.whiteBalanceTint}); + this.pullData("/video/whiteBalanceTint").then((value) => {this.WhiteBalanceTint = value.whiteBalanceTint; this.updateUIWhiteBalance()}); } getND() { - this.pullData("/video/ndFilter").then((value) => {this.NDStop = value.stop}); + this.pullData("/video/ndFilter").then((value) => {this.NDStop = value.stop; this.updateUINDStop()}); this.pullData("/video/ndFilter/displayMode").then((value) => {this.NDMode = value.displayMode}); } getShutter() { - this.pullData("/video/shutter").then((value) => {this.shutter = value}); + this.pullData("/video/shutter").then((value) => {this.shutter = value; this.updateUIshutter()}); } getAutoExposureMode() { - this.pullData("/video/autoExposure").then((value) => {this.AutoExposureMode = value}); + this.pullData("/video/autoExposure").then((value) => {this.AutoExposureMode = value; this.updateUIAutoExposureMode()}); } getColorCorrection() { @@ -346,7 +372,7 @@ class BMDCamera { this.pullData("/colorCorrection/offset").then((value) => {this.CCoffset = value}); this.pullData("/colorCorrection/contrast").then((value) => {this.CCcontrast = value}); this.pullData("/colorCorrection/color").then((value) => {this.CCcolor = value}); - this.pullData("/colorCorrection/lumaContribution").then((value) => {this.CClumacontribution = value}); + this.pullData("/colorCorrection/lumaContribution").then((value) => {this.CClumacontribution = value; this.updateUIColorCorrection()}); } getAllInfo() { @@ -355,7 +381,6 @@ class BMDCamera { this.getSupportedCodecFormats(); this.getSupportedVideoFormats(); this.getTransportMode(); - this.getIsPlaying(); this.getPlaybackState(); this.getRecordState(); this.getTimecode(); @@ -373,14 +398,130 @@ class BMDCamera { this.getColorCorrection(); } - // =============== Other Commands ======================= - doAutoFocus() { - this.pushData("/lens/focus/doAutoFocus") + // =============== SETTERS ================== + + // name, hostname, APIaddress, index should never have to be set + + setCodecFormat(newCodecFormatObject) { + this.pushData("/system/codecFormat",newCodecFormatObject).then(() => sleep(1000).then(() => this.getCodecFormat())); } - /* Timer Stuff */ - everySecond() { - this.refresh(); + setVideoFormat(newVideoFormatObject) { + this.pushData("/system/videoFormat",newVideoFormatObject).then(() => sleep(1000).then(() => this.getCodecFormat())); + } + + setTransportMode(newTransportModeString) { + this.pushData("/transports/0",{"mode": newTransportModeString}).then(() => sleep(1000).then(() => this.getTransportMode())); + } + + setPlaybackState(playbackStateObject) { + this.pushData("/transports/0/playback",playbackStateObject).then(() => sleep(1000).then(() => this.getPlaybackState())); + } + + sendPresetFile(file) { + sendRequest("POST",this.APIAddress+"/presets",file) + } + + setActivePreset(presetString) { + this.pushData("/presets/active",{"preset": presetString}).then(() => sleep(1000).then(() => this.getActivePreset())); + } + + setAperture(apertureNormalisedFloat) { + this.pushData("/lens/iris",{"normalised": apertureNormalisedFloat}).then(() => sleep(1000).then(() => this.getAperture())); + } + + setZoom(zoomNormalisedFloat) { + this.pushData("/lens/zoom",{"normalised": zoomNormalisedFloat}).then(() => sleep(1000).then(() => this.getZoom())); + } + + setFocus(focusNormalisedFloat) { + this.pushData("/lens/focus",{"normalised": focusNormalisedFloat}).then(() => sleep(1000).then(() => this.getFocus())); + } + + setISO(ISOint) { + this.pushData("/video/iso",{"iso":ISOint}).then(() => sleep(1000).then(() => this.getISO())); + } + + setGain(gainInt) { + this.pushData("/video/gain",{"gain":gainInt}).then(() => sleep(1000).then(() => this.getGain())); + } + + setWhiteBalance(whiteBalanceInt, whiteBalanceTintInt) { + this.pushData("/video/whiteBalance",{"whiteBalance": whiteBalanceInt}); + this.pushData("/video/whiteBalanceTint",{"whiteBalanceTint": whiteBalanceTintInt}).then(() => sleep(1000).then(() => this.getWhiteBalance())); + } + + setND(NDstopInt) { + this.pushData("/video/ndFilter",{"stop": NDstopInt}).then(() => sleep(1000).then(() => this.getND())); + } + + setNDDisplayMode(displayModeString) { + this.pushData("/video/ndFilter/displayMode",{"displayMode": displayModeString}).then(() => sleep(1000).then(() => this.getND())); + } + + // Accepts JSON obejcts with either shutterSpeed or shutterAngle properties + // Note that shutterAngle is 100x the displayed value + setShutter(shutterObject) { + this.pushData("/video/shutter",shutterObject).then(() => sleep(1000).then(() => this.getShutter())); + } + + setAutoExposureMode(AEmodeObject) { + this.pushData("/video/autoExposure",AEmodeObject).then(() => sleep(1000).then(() => this.getAutoExposureMode())); + } + + setCCLift(CCliftObject) { + this.pushData("/colorCorrection/lift",CCliftObject).then(() => sleep(1000).then(() => this.getColorCorrection())); + } + + setCCGamma(CCgammaObject) { + this.pushData("/colorCorrection/gamma",CCgammaObject).then(() => sleep(1000).then(() => this.getColorCorrection())); + } + + setCCGain(CCgainObject) { + this.pushData("/colorCorrection/gain",CCgainObject).then(() => sleep(1000).then(() => this.getColorCorrection())); + } + + setCCOffset(CCoffsetObject) { + this.pushData("/colorCorrection/offset",CCoffsetObject).then(() => sleep(1000).then(() => this.getColorCorrection())); + } + + setCCContrast(CCcontrastObject) { + this.pushData("/colorCorrection/contrast",CCcontrastObject).then(() => sleep(1000).then(() => this.getColorCorrection())); + } + + setCCColor(CCcolorObject) { + this.pushData("/colorCorrection/color",CCcolorObject).then(() => sleep(1000).then(() => this.getColorCorrection())); + } + + setCCLumaContribuion(CClumacontributionObject) { + this.pushData("/colorCorrection/lumaContribution",CClumacontributionObject).then(() => sleep(1000).then(() => this.getColorCorrection())); + } + + // =============== Other Commands ======================= + doAutoFocus() { + this.pushData("/lens/focus/doAutoFocus").then(() => sleep(1500).then(() => this.getFocus())); + } + + play() { + this.pushData("/transports/0/play").then(() => sleep(1000).then(() => this.getPlaybackState())); + } + + record() { + this.pushData("/transports/0/record",{"recording": true}).then(() => { + sleep(2000).then(() => this.getRecordState()); + }); + } + + stopTransport() { + this.pushData("/transports/0/stop").then(() => { + sleep(2000).then(() => this.getPlaybackState()); + }); + } + + stopRecord() { + this.pushData("/transports/0/record",{"recording": false}).then(() => { + sleep(2000).then(() => this.getRecordState()); + }); } } @@ -398,8 +539,27 @@ async function sendRequest(method, url, data) { } } - xhttp.open(method, url, false); - xhttp.send(JSON.stringify(data)); + // Don't keep making API calls for unimplemented features + if (cameras[ci]) { + // First check if the camera exists. + if (cameras[ci].UnimplementedFunctionality.indexOf(url) < 0) { + // If everything is honky dory + + xhttp.open(method, url, false); + xhttp.send(JSON.stringify(data)); + } else { + // If everything is not honky dory + // do nothing + } + + if ((!responseObject) || (Object.hasOwn(responseObject,'error') && responseObject.error == "Not implemented for this device")) { + cameras[ci].UnimplementedFunctionality.push(url); + } + + } else { + xhttp.open(method, url, false); + xhttp.send(JSON.stringify(data)); + } return responseObject; } diff --git a/web-ui/Screenshot 2024-06-12 171720.png b/web-ui/Screenshot 2024-06-12 171720.png new file mode 100644 index 0000000..27d7cf6 Binary files /dev/null and b/web-ui/Screenshot 2024-06-12 171720.png differ diff --git a/web-ui/index.html b/web-ui/index.html index b443a8b..6b9896e 100644 --- a/web-ui/index.html +++ b/web-ui/index.html @@ -24,71 +24,268 @@
- + CAM1 + | + CAM2 + | + CAM3 + | + CAM4 + | + CAM5 + | + CAM6 + | + CAM7 + | + CAM8
-
-
-

CAM1

+
+
+

CAM1

-
+
+ + Lift +
+ +
+ 0.00 + 0.00 + 0.00 + 0.00 +
+ +
+ Gamma +
+ +
+ 0.00 + 0.00 + 0.00 + 0.00 +
+ +
+ + Gain +
+ +
+ 0.00 + 0.00 + 0.00 + 0.00 +
+ +
+ + + Offset +
+ +
+ 0.00 + 0.00 + 0.00 + 0.00 +
+ +
-
+
FILTER - - 0 +
+ + 0 + +
GAIN - - +0db +
+ + +0db + +
SHUTTER - - 1/50 +
+ + 1/50 + +
BALANCE - - 5600K +
+ + 5600K + +
-
+
FOCUS - - + +
IRIS - - X.X + + X.X
ZOOM - - XXmm + + XXmm
-
-
-

TIMECODE

+
+
+

CAMERA NAME

+
+ + + + + + + + +
+

TIMECODE

-
- Hostname: - - + +
+
+

Connection

+ + + + + + + + + +
Hostname + + +
Send API Call + + + + + + + + + +
+
+ +
+

Presets

+ + + + + + + + + +
Preset Select + +
Upload a preset file
+
+ +
+

Exposure

+ + + + + + + + + + + + + +
ISO
AE Mode + +
AE Type + +
+ +
+ +
+

Contrast

+ + + + + + + + + +
Pivot
Adjust
+
+ +
+

Color

+ + + + + + + + + + + + + +
Hue
Saturation
Luma Contribution
+
@@ -97,6 +294,11 @@ \ No newline at end of file diff --git a/web-ui/style.css b/web-ui/style.css index 0e34d91..45e8201 100644 --- a/web-ui/style.css +++ b/web-ui/style.css @@ -1,3 +1,5 @@ +/* ============= WHOLE PAGE STYLES ================== */ + /* Load NotoSansDisplay Font from resources */ @font-face { font-family: 'NotoSansDisplay'; @@ -7,6 +9,7 @@ body { font-family: 'NotoSansDisplay', sans-serif; + font-weight: 100; margin: 0px; overflow: hidden; background: #181818; @@ -22,6 +25,91 @@ body { display: inline-flex; } +/* Inputs */ + +input[type=text] { + border-radius: 0.5vh; + background: rgb(30, 30, 30); + color: white; + height: 2em; + width: 10vw; + border: 1px solid rgb(20, 20, 20); + text-align: center; + font-family: 'NotoSansDisplay', sans-serif; + outline: none; + margin: 0px 0.5vw; +} + +input[type=text]:focus { + border: 1px solid rgb(150, 58, 0); +} + +input[type=number] { + border-radius: 0.5vh; + background: rgb(30, 30, 30); + color: white; + height: 2em; + width: 4.666vw; + border: 1px solid rgb(20, 20, 20); + text-align: center; + font-family: 'NotoSansDisplay', sans-serif; + outline: none; +} + +input[type=number]:focus { + border: 1px solid rgb(150, 58, 0); +} + +input[type=range][orient=vertical] { + writing-mode: vertical-lr; direction: rtl; + width: 2vw; + height: 80%; +} + +select { + border-radius: 0.5vh; + background: rgb(30, 30, 30); + color: white; + height: 2em; + width: 5vw; + border: 1px solid rgb(20, 20, 20); + text-align: center; + font-family: 'NotoSansDisplay', sans-serif; + outline: none; +} + +select:focus { + border: 1px solid rgb(150, 58, 0); +} + +button { + font-family: 'NotoSansDisplay', sans-serif; + background: #181818; + background: linear-gradient(0deg, #232323 0%, #404040 100%); + border: 0.3vh solid black; + outline: 0.3vh solid #404040; + color: white; + height: fit-content; + width: fit-content; + border-radius: 0.4em; + padding: 0.5vh 1vw; + margin: 1vh; +} + +button:hover { + background: #313131; + background: linear-gradient(0deg, #313131 0%, #4d4d4d 100%); +} + +button:active { + background: #181818; + box-shadow: inset 0 0 1em #090909; +} + +input[type=file]:focus { + border: 1px solid rgb(150, 58, 0); +} + /* Horizontal Container Styles */ #headerContainer { background: #181818; @@ -34,9 +122,9 @@ body { } #headerContainer h1 { - font-weight: 100; color: white; margin-left: 1.3vw; + font-weight: 100; } #cameraSelectContainer { @@ -44,6 +132,27 @@ body { border: 1px solid black; width: 100%; height: 3.53vh; + color: #474747; + font-size: 1em; + align-items: center; + justify-content: center; +} + +#cameraSelectContainer span { + height: fit-content; +} + +#cameraSelectContainer .camSelectSeparator { + margin: 0px 0.5em; +} + +.cameraSwitchLabel a { + text-decoration: none; + color: #474747; +} + +.cameraSwitchLabel.selectedCam a { + color: #e66c01; } #allCamerasContainer { @@ -64,10 +173,26 @@ body { height: 5vh; position: fixed; bottom: 0; + align-items: center; + justify-content: space-between; +} + +#footerContainer button { + padding: 0.4em 0.8em; + font-size: x-small; +} + +#footerLinks span { + margin-right: 1.25vw; +} + +#footerLinks a { + text-decoration: none; + color: #e66c01; } /* Camera Controls Container */ -.cameraControlsContainer { +#cameraControlsContainer { width: 15vw; height: 100%; background: #282828; @@ -76,39 +201,98 @@ body { flex-shrink: 0; } -.cameraControlsContainer.selectedCam { - background: #323232; -} - -.liveCam .cameraControlHeadContainer { +.liveCam { background: rgb(184,3,16); background: linear-gradient(90deg, rgba(184,3,16,1) 0%, rgba(255,0,19,1) 15%, rgba(255,0,19,1) 85%, rgba(184,3,16,1) 100%); } -.cameraControlHeadContainer { +#cameraControlHeadContainer { width: 100%; height: 5vh; border-bottom: 2px solid black; align-items: center; + color: white; } -.cameraName { - font-weight: 100; - color: white; +h2 { margin-inline-start: 0.6em; margin-inline-end: 0.6em; + font-weight: 100; +} + +#cameraName { + } /* Color Correction Section */ -.cameraControlColorCorrectionContainer { +#cameraControlColorCorrectionContainer { width: 100%; height: 33vh; + flex-direction: column; + align-items: center; + justify-content: space-between; +} + +#cameraControlLGGTabs { + margin-top: 2vh; + border: 1px solid #101010; + border-radius: 2.5vh; + overflow: hidden; +} + + +#cameraControlLGGTabs a { + background: #181818; + background: linear-gradient(0deg, #181818 0%, #303030 100%); + + padding: 0.1vh 1.25vw 0.25vh 1.25vw; + + border-left: 1px solid #101010; + + text-decoration: none; + color: #474747; +} + +#cameraControlLGGTabs a.selectedTab { + color: #e66c01; +} + +.ccExposureSettingValueContainer .expAdjArr { + text-decoration: none; + color: #60606000; +} + +.ccExposureSettingValueContainer:hover .expAdjArr { + color: #606060ff; +} + +.ccExposureSettingValueContainer:hover .expAdjArr:hover { + color: #474747; +} + +.ccExposureSettingValueContainer:hover .expAdjArr:active { + color: #e66c01; +} + +#cameraControlColorCorrectionBottomContainer { + margin-bottom: 1em; + display: inline-flex; + align-items: center; +} + +#cameraControlColorCorrectionBottomContainer button { + margin: 0px 0.5em; +} + +#cameraControlColorCorrectionNumbersContainer span { + margin: 0px 0.5em; + text-decoration: underline 3px; } /* Exposure Section */ -.cameraControlExposureContainer { +#cameraControlExposureContainer { width: 100%; - height: 4.4vh; + height: 4.7vh; background-color: #171717; border-top: 1px solid #2d2d2d; border-bottom: 1px solid #2d2d2d; @@ -117,11 +301,6 @@ body { overflow: hidden; } -.selectedCam .cameraControlExposureContainer { - border-top: 1px solid #3a3a3a; - border-bottom: 1px solid #3a3a3a; -} - .ccExposureSettingContainer { display: flex; color: white; @@ -141,7 +320,7 @@ body { } /* Lens Stuff */ -.cameraControlLensContainer { +#cameraControlLensContainer { width: 100%; height: 41.9vh; border-bottom: 1px solid black; @@ -159,19 +338,20 @@ body { margin-bottom: 1em; } -.lensSliderContainer button { - margin-top: 1em; - margin-bottom: 1em; +.circleButton { + width: 2em; + height: 2em; + border-radius: 1em; + padding: 0; + margin: 1em 0; } -input[type=range][orient=vertical] { - -webkit-appearance: slider-vertical; - width: 2vw; - height: 80%; +#transportControls .circleButton { + margin: 0 0.5em; } /* Right side (expanded) */ -.cameraControlsContainerExpanded { +#cameraControlsContainerExpanded { width: 84.75vw; height: 100%; background: #282828; @@ -180,39 +360,43 @@ input[type=range][orient=vertical] { flex-shrink: 0; } -.cameraControlExpandedHeadContainer { +#cameraControlExpandedHeadContainer { width: 100%; height: 5vh; border-bottom: 2px solid black; align-items: center; - justify-content: center; + justify-content: space-between; } -.timecodeLabel { +#cameraControlExpandedBodyContainer { + flex-direction: column; + display: inline-flex; + height: inherit; + justify-content: space-around; +} + +#timecodeLabel { + +} + +/* Table Controls */ + +.tableControl { + margin-left: 1.5vw; +} + +.tableControl h3 { font-weight: 100; - color: white; - margin-inline-start: 0.6em; - margin-inline-end: 0.6em; + margin: 0.5vh 0vw; } -/* Connection Settings */ -.connectionContainer { - margin: 1.5vw; +table, td { + margin-left: 0.5vw; + /* border: 1px solid white; */ + border-collapse: collapse; + padding: 0.1vw 1vw; } -input[type=text] { - border-radius: 0.5vh; - background: rgb(30, 30, 30); - color: white; - height: 2em; - width: 10vw; - border: 1px solid rgb(20, 20, 20); - margin-left: 1vw; - text-align: center; - font-family: 'NotoSansDisplay', sans-serif; - outline: none; -} - -input[type=text]:focus { - border: 1px solid rgb(150, 58, 0); +td, tr { + align-items: center; } \ No newline at end of file diff --git a/web-ui/web-ui.js b/web-ui/web-ui.js index 41c1c23..00ac121 100644 --- a/web-ui/web-ui.js +++ b/web-ui/web-ui.js @@ -1,20 +1,38 @@ /* Global variables */ var cameras = []; var ci = 0; +var ccMode = 0; function bodyOnLoad() { - //let intervalID = setInterval(timerCallFunction, 1000); + let intervalIDOne = setInterval(timerCallFunction1, 1000); // Tem second timer for refreshing everything + let intervalIDTen = setInterval(timerCallFunction10, 10000); // Tem second timer for refreshing everything - let newCamHostname = document.getElementsByClassName("hostnameInput")[ci].value; + let newCamHostname = document.getElementById("hostnameInput").value; if (newCamHostname) { cameras[ci] = new BMDCamera(newCamHostname,ci); } } -// function timerCallFunction() { -// cameras.forEach((camera) => camera.everySecond()); -// } +// One Second Timer Call +function timerCallFunction1() { + if (cameras[ci]) { + cameras[ci].getRecordState(); + cameras[ci].getPlaybackState(); + cameras[ci].getTimecode(); + + cameras[ci].updateUIRecordState(); + cameras[ci].updateUIPlaybackState(); + cameras[ci].updateUITimecode(); + } +} + +// Ten Second Timer Call +function timerCallFunction10() { + if (cameras[ci]) { + cameras[ci].refresh(); + } +} function textInputTrigger(element) { if (event.key === 'Enter') { @@ -22,6 +40,124 @@ function textInputTrigger(element) { } } +function switchCamera(index) { + ci = index; + + if (cameras[ci]) { + cameras[ci].refresh(); + } + + for (var i = 0; i < 8; i++) { + if (i == ci) { + document.getElementsByClassName("cameraSwitchLabel")[i].classList.add("selectedCam"); + } else { + document.getElementsByClassName("cameraSwitchLabel")[i].classList.remove("selectedCam"); + } + } + + document.getElementById("cameraNumberLabel").innerHTML = "CAM"+(ci+1); +} + +function setCCMode(mode) { + if (mode == 0) { + // Lift + + } else if (mode == 1) { + // Gamma + + } else { + // Gain + + } + + for (var i = 0; i < 3; i++) { + if (i == mode) { + document.getElementsByClassName("ccTabLabel")[i].classList.add("selectedTab"); + } else { + document.getElementsByClassName("ccTabLabel")[i].classList.remove("selectedTab"); + } + } +} + +/* Control Calling Functions */ + +function decreaseND() { + cameras[ci].setND(cameras[ci].NDStop-2); +} + +function increaseND() { + cameras[ci].setND(cameras[ci].NDStop+2); +} + +function decreaseGain() { + cameras[ci].setGain(cameras[ci].gain-2); +} + +function increaseGain() { + cameras[ci].setGain(cameras[ci].gain+2); +} + +function decreaseShutter() { + let cam = cameras[ci]; + + if ('shutterSpeed' in cam.shutter) { + cam.setShutter({"shutterSpeed":cam.shutter.shutterSpeed+10}); + } else { + cam.setShutter({"shutterAngle": cam.shutter.shutterAngle-1000}); + } +} + +function increaseShutter() { + let cam = cameras[ci]; + + if ('shutterSpeed' in cam.shutter) { + cam.setShutter({"shutterSpeed":cam.shutter.shutterSpeed-10}); + } else { + cam.setShutter({"shutterAngle": cam.shutter.shutterAngle+1000}); + } +} + +function decreaseWhiteBalance() { + cameras[ci].setWhiteBalance(cameras[ci].WhiteBalance-50,cameras[ci].WhiteBalanceTint); +} + +function increaseWhiteBalance() { + cameras[ci].setWhiteBalance(cameras[ci].WhiteBalance+50,cameras[ci].WhiteBalanceTint); +} + +// 0: lift, 1: gamma, 2: gain, 3: offset +function setCCFromUI(which) { + let lumaFloat = parseFloat(document.getElementsByClassName("CClumaLabel")[which].innerHTML); + let redFloat = parseFloat(document.getElementsByClassName("CCredLabel")[which].innerHTML); + let greenFloat = parseFloat(document.getElementsByClassName("CCgreenLabel")[which].innerHTML); + let blueFloat = parseFloat(document.getElementsByClassName("CCblueLabel")[which].innerHTML); + + let ccobject = {"red": redFloat, "green": greenFloat, "blue": blueFloat, "luma": lumaFloat}; + + if (which == 0) { + cameras[ci].setCCLift(ccobject); + } else if (which == 1) { + cameras[ci].setCCGamma(ccobject); + } else if (which == 2) { + cameras[ci].setCCGain(ccobject); + } else { + cameras[ci].setCCOffset(ccobject); + } +} + +// 0: lift, 1: gamma, 2: gain, 3: offset +function resetCC(which) { + if (which == 0) { + cameras[ci].setCCLift({"red": 0.0, "green": 0.0, "blue": 0.0, "luma": 0.0}); + } else if (which == 1) { + cameras[ci].setCCGamma({"red": 0.0, "green": 0.0, "blue": 0.0, "luma": 0.0}); + } else if (which == 2) { + cameras[ci].setCCGain({"red": 1.0, "green": 1.0, "blue": 1.0, "luma": 1.0}); + } else { + cameras[ci].setCCOffset({"red": 0.0, "green": 0.0, "blue": 0.0, "luma": 0.0}); + } +} + function makeFakeCamera() { cam = new BMDCamera("Studio-Camera-6K-Pro.local",0) return Object.assign(cam,{ @@ -32,7 +168,6 @@ function makeFakeCamera() { "transportMode": { "mode": "InputPreview" }, - "isPlaying": false, "playbackState": { "loop": false, "position": 0,