) => void;
+ displayValue: string;
+ }
+
+ function renderSlider(sliderProps: ISliderProps) {
+ return (
+
+ {sliderProps.title}
+
+ ) =>
+ sliderProps.setValue(Number.parseInt(e.currentTarget.value, 10))
+ }
+ />
+
+ sliderProps.setValue(sliderProps.range.default)}
+ onKeyPress={() => sliderProps.setValue(sliderProps.range.default)}
+ >
+ {sliderProps.displayValue}
+
+
+ );
+ }
+
+ function renderBlur() {
+ return renderSlider({
+ title: "Blur",
+ range: blurRange,
+ value: blurValue,
+ setValue: setBlurValue,
+ displayValue: `${blurValue / blurRange.divider}px`,
+ });
+ }
+
+ function renderContrast() {
+ return renderSlider({
+ title: "Contrast",
+ className: "contrast-slider",
+ range: contrastRange,
+ value: contrastValue,
+ setValue: setContrastValue,
+ displayValue: `${contrastValue / brightnessRange.divider}%`,
+ });
+ }
+
+ function renderBrightness() {
+ return renderSlider({
+ title: "Brightness",
+ className: "brightness-slider",
+ range: brightnessRange,
+ value: brightnessValue,
+ setValue: setBrightnessValue,
+ displayValue: `${brightnessValue / brightnessRange.divider}%`,
+ });
+ }
+
+ function renderGammaSlider() {
+ return renderSlider({
+ title: "Gamma",
+ className: "gamma-slider",
+ range: gammaRange,
+ value: gammaValue,
+ setValue: setGammaValue,
+ displayValue: `${(gammaValue - gammaRange.default) / gammaRange.divider}`,
+ });
+ }
+
+ function renderSaturate() {
+ return renderSlider({
+ title: "Saturation",
+ className: "saturation-slider",
+ range: saturateRange,
+ value: saturateValue,
+ setValue: setSaturateValue,
+ displayValue: `${saturateValue / saturateRange.divider}%`,
+ });
+ }
+
+ function renderHueRotateSlider() {
+ return renderSlider({
+ title: "Hue",
+ className: "hue-rotate-slider",
+ range: hueRotateRange,
+ value: hueRotateValue,
+ setValue: setHueRotateValue,
+ displayValue: `${hueRotateValue / hueRotateRange.divider}\xB0`,
+ });
+ }
+
+ function renderWhiteBalance() {
+ return renderSlider({
+ title: "Warmth",
+ className: "white-balance-slider",
+ range: whiteBalanceRange,
+ value: whiteBalanceValue,
+ setValue: setWhiteBalanceValue,
+ displayValue: `${
+ (whiteBalanceValue - whiteBalanceRange.default) /
+ whiteBalanceRange.divider
+ }`,
+ });
+ }
+
+ function renderRedSlider() {
+ return renderSlider({
+ title: "Red",
+ className: "red-slider",
+ range: colourRange,
+ value: redValue,
+ setValue: setRedValue,
+ displayValue: `${
+ (redValue - colourRange.default) / colourRange.divider
+ }%`,
+ });
+ }
+
+ function renderGreenSlider() {
+ return renderSlider({
+ title: "Green",
+ className: "green-slider",
+ range: colourRange,
+ value: greenValue,
+ setValue: setGreenValue,
+ displayValue: `${
+ (greenValue - colourRange.default) / colourRange.divider
+ }%`,
+ });
+ }
+
+ function renderBlueSlider() {
+ return renderSlider({
+ title: "Blue",
+ className: "blue-slider",
+ range: colourRange,
+ value: blueValue,
+ setValue: setBlueValue,
+ displayValue: `${
+ (blueValue - colourRange.default) / colourRange.divider
+ }%`,
+ });
+ }
+
+ function renderRotate() {
+ return renderSlider({
+ title: "Rotate",
+ range: rotateRange,
+ value: rotateValue,
+ setValue: setRotateValue,
+ displayValue: `${
+ (rotateValue - rotateRange.default) / rotateRange.divider
+ }\xB0`,
+ });
+ }
+
+ function renderScale() {
+ return renderSlider({
+ title: "Scale",
+ range: scaleRange,
+ value: scaleValue,
+ setValue: setScaleValue,
+ displayValue: `${scaleValue / scaleRange.divider}%`,
+ });
+ }
+
+ function renderAspectRatio() {
+ return renderSlider({
+ title: "Aspect",
+ range: aspectRatioRange,
+ value: aspectRatioValue,
+ setValue: setAspectRatioValue,
+ displayValue: `${
+ (aspectRatioValue - aspectRatioRange.default) / aspectRatioRange.divider
+ }`,
+ });
+ }
+
+ function onRotateAndScale(direction: number) {
+ if (direction === 0) {
+ // Left -90
+ setRotateValue(1);
+ } else {
+ // Right +90
+ setRotateValue(3);
+ }
+
+ // Calculate Required Scaling.
+ const sceneWidth = props.scene.file.width ?? 1;
+ const sceneHeight = props.scene.file.height ?? 1;
+ const sceneAspectRatio = sceneWidth / sceneHeight;
+ const sceneNewAspectRatio = sceneHeight / sceneWidth;
+
+ const playerId = JWUtils.playerID;
+ const playerVideoElement = document
+ .getElementById(playerId)
+ ?.getElementsByClassName("jw-video")[0];
+
+ const playerWidth = playerVideoElement?.clientWidth ?? 1;
+ const playerHeight = playerVideoElement?.clientHeight ?? 1;
+ const playerAspectRation = playerWidth / playerHeight;
+
+ // rs > ri ? (wi * hs/hi, hs) : (ws, hi * ws/wi)
+ // Determine if video is currently constrained by player height or width.
+ let scaledVideoHeight = 0;
+ let scaledVideoWidth = 0;
+ if (playerAspectRation > sceneAspectRatio) {
+ // Video has it's width scaled
+ // Video is constrained by it's height
+ scaledVideoHeight = playerHeight;
+ scaledVideoWidth = (playerHeight / sceneHeight) * sceneWidth;
+ } else {
+ // Video has it's height scaled
+ // Video is constrained by it's width
+ scaledVideoWidth = playerWidth;
+ scaledVideoHeight = (playerWidth / sceneWidth) * sceneHeight;
+ }
+
+ // but now the video is rotated
+ let scaleFactor = 1;
+ if (playerAspectRation > sceneNewAspectRatio) {
+ // Rotated video will be constrained by it's height
+ // so we need to scaledVideoWidth to match the player height
+ scaleFactor = playerHeight / scaledVideoWidth;
+ } else {
+ // Rotated video will be constrained by it's width
+ // so we need to scaledVideoHeight to match the player width
+ scaleFactor = playerWidth / scaledVideoHeight;
+ }
+
+ setScaleValue(scaleFactor * 100);
+ }
+
+ function renderRotateAndScale() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ }
+
+ function onResetFilters() {
+ setContrastValue(contrastRange.default);
+ setBrightnessValue(brightnessRange.default);
+ setGammaValue(gammaRange.default);
+ setSaturateValue(saturateRange.default);
+ setHueRotateValue(hueRotateRange.default);
+ setWhiteBalanceValue(whiteBalanceRange.default);
+ setRedValue(colourRange.default);
+ setGreenValue(colourRange.default);
+ setBlueValue(colourRange.default);
+ setBlurValue(blurRange.default);
+ }
+
+ function onResetTransforms() {
+ setScaleValue(scaleRange.default);
+ setRotateValue(rotateRange.default);
+ setAspectRatioValue(aspectRatioRange.default);
+ }
+
+ function renderResetButton() {
+ return (
+
+
+
+
+
+
+
+
+ );
+ }
+
+ function renderFilterContainer() {
+ return ;
+ }
+
+ // On render update video style.
+ updateVideoFilters();
+ updateVideoStyle();
+
+ return (
+
+
+
+ Filters
+
+
+ {renderBrightness()}
+ {renderContrast()}
+ {renderGammaSlider()}
+ {renderSaturate()}
+ {renderHueRotateSlider()}
+ {renderWhiteBalance()}
+ {renderRedSlider()}
+ {renderGreenSlider()}
+ {renderBlueSlider()}
+ {renderBlur()}
+
+
+ Transforms
+
+
+ {renderRotate()}
+ {renderScale()}
+ {renderAspectRatio()}
+
+
+ Actions
+
+
+ {renderRotateAndScale()}
+ {renderResetButton()}
+ {renderFilterContainer()}
+
+ );
+};
diff --git a/ui/v2.5/src/components/Scenes/styles.scss b/ui/v2.5/src/components/Scenes/styles.scss
index ba557d9a1..6368a68ab 100644
--- a/ui/v2.5/src/components/Scenes/styles.scss
+++ b/ui/v2.5/src/components/Scenes/styles.scss
@@ -266,6 +266,191 @@ textarea.scene-description {
word-wrap: break-word;
}
+input[type="range"].filter-slider {
+ height: 100%;
+ margin: 0;
+ padding-left: 0;
+ padding-right: 0;
+}
+
+@mixin contrast-slider() {
+ background: rgb(255, 255, 255);
+ background: linear-gradient(
+ -1deg,
+ rgba(255, 255, 255, 1) 0%,
+ rgba(255, 255, 255, 1) 40%,
+ rgba(0, 0, 0, 1) 60%,
+ rgba(0, 0, 0, 1) 100%
+ ),
+ linear-gradient(90deg, rgba(61, 61, 61, 1) 0%, rgba(255, 255, 255, 0) 100%);
+ background-blend-mode: color;
+}
+
+input[type="range"].contrast-slider {
+ &::-webkit-slider-runnable-track {
+ @include contrast-slider;
+ }
+
+ &::-moz-range-track {
+ @include contrast-slider;
+ }
+
+ &::-ms-track {
+ @include contrast-slider;
+ }
+}
+
+@mixin brightness-slider() {
+ background: rgb(41, 41, 41);
+ background: linear-gradient(
+ 90deg,
+ rgba(41, 41, 41, 1) 0%,
+ rgba(255, 255, 255, 1) 100%
+ );
+}
+
+input[type="range"].brightness-slider {
+ &::-webkit-slider-runnable-track {
+ @include brightness-slider;
+ }
+
+ &::-moz-range-track {
+ @include brightness-slider;
+ }
+
+ &::-ms-track {
+ @include brightness-slider;
+ }
+}
+
+@mixin saturation-slider() {
+ background: rgb(198, 198, 199);
+ background: linear-gradient(
+ 90deg,
+ rgba(198, 198, 199, 1) 0%,
+ rgba(255, 71, 71, 1) 100%
+ );
+}
+
+input[type="range"].saturation-slider {
+ &::-webkit-slider-runnable-track {
+ @include saturation-slider;
+ }
+
+ &::-moz-range-track {
+ @include saturation-slider;
+ }
+
+ &::-ms-track {
+ @include saturation-slider;
+ }
+}
+
+@mixin hue-rotate-slider() {
+ background: rgb(198, 198, 199);
+ background: linear-gradient(
+ to right,
+ orange,
+ yellow,
+ green,
+ cyan,
+ blue,
+ violet
+ );
+}
+
+input[type="range"].hue-rotate-slider {
+ &::-webkit-slider-runnable-track {
+ @include hue-rotate-slider;
+ }
+
+ &::-moz-range-track {
+ @include hue-rotate-slider;
+ }
+
+ &::-ms-track {
+ @include hue-rotate-slider;
+ }
+}
+
+@mixin white-balance-slider() {
+ background: rgb(90, 138, 210);
+ background: linear-gradient(
+ 90deg,
+ rgba(90, 138, 210, 1) 0%,
+ rgba(83, 72, 72, 1) 50%,
+ rgba(252, 186, 8, 1) 100%
+ );
+}
+
+input[type="range"].white-balance-slider {
+ &::-webkit-slider-runnable-track {
+ @include white-balance-slider;
+ }
+
+ &::-moz-range-track {
+ @include white-balance-slider;
+ }
+
+ &::-ms-track {
+ @include white-balance-slider;
+ }
+}
+
+@mixin red-slider() {
+ background: rgb(255, 0, 0);
+}
+
+input[type="range"].red-slider {
+ &::-webkit-slider-runnable-track {
+ @include red-slider;
+ }
+
+ &::-moz-range-track {
+ @include red-slider;
+ }
+
+ &::-ms-track {
+ @include red-slider;
+ }
+}
+
+@mixin green-slider() {
+ background: rgb(0, 255, 0);
+}
+
+input[type="range"].green-slider {
+ &::-webkit-slider-runnable-track {
+ @include green-slider;
+ }
+
+ &::-moz-range-track {
+ @include green-slider;
+ }
+
+ &::-ms-track {
+ @include green-slider;
+ }
+}
+
+@mixin blue-slider() {
+ background: rgb(0, 0, 255);
+}
+
+input[type="range"].blue-slider {
+ &::-webkit-slider-runnable-track {
+ @include blue-slider;
+ }
+
+ &::-moz-range-track {
+ @include blue-slider;
+ }
+
+ &::-ms-track {
+ @include blue-slider;
+ }
+}
+
@media (min-width: 1200px), (max-width: 575px) {
.performer-card .flag-icon {
height: 1.33rem;