diff --git a/public/configuration.json b/public/configuration.json index 7debfc8a..8be03e62 100644 --- a/public/configuration.json +++ b/public/configuration.json @@ -402,6 +402,226 @@ "isAmbassadorOnly": false } ], + "camera.available.effects": [ + { + "name":"dark_sepia", + "colorMatrix": [0.4, 0.4, 0.1, 0, 110, 0.3, 0.4, 0.1, 0, 30, 0.3, 0.2, 0.1, 0, 0, 0, 0, 0, 1, 0], + "minLevel": 0, + "enabled": true + }, + { + "name":"increase_saturation", + "colorMatrix": [2, -0.5, -0.5, 0, 0, -0.5, 2, -0.5, 0, 0, -0.5, -0.5, 2, 0, 0, 0, 0, 0, 1, 0], + "minLevel": 0, + "enabled": true + }, + { + "name":"increase_contrast", + "colorMatrix": [1.5, 0, 0, 0, -50, 0, 1.5, 0, 0, -50, 0, 0, 1.5, 0, -50, 0, 0, 0, 1.5, 0], + "minLevel": 0, + "enabled": true + }, + { + "name":"shadow_multiply_02", + "minLevel": 0, + "enabled": true + }, + { + "name":"color_1", + "colorMatrix": [0.393, 0.769, 0.189, 0, 0, 0.349, 0.686, 0.168, 0, 0, 0.272, 0.534, 0.131, 0, 0, 0, 0, 0, 1, 0], + "minlevel": 1, + "enabled": true + }, + { + "name":"hue_bright_sat", + "colorMatrix": [1, 0.6, 0.2, 0, -50, 0.2, 1, 0.6, 0, -50, 0.6, 0.2, 1, 0, -50, 0, 0, 0, 1, 0], + "minlevel": 1, + "enabled": true + }, + { + "name":"hearts_hardlight_02", + "minlevel": 1, + "enabled": true + }, + { + "name":"texture_overlay", + "minlevel": 1, + "enabled": true + }, + { + "name":"pinky_nrm", + "minlevel": 1, + "enabled": true + }, + { + "name":"color_2", "colorMatrix": [0.333, 0.333, 0.333, 0, 0, 0.333, 0.333, 0.333, 0, 0, 0.333, 0.333, 0.333, 0, 0, 0, 0, 0, 1, 0], + "minlevel": 2, + "enabled": true + }, + { + "name":"night_vision", "colorMatrix": [0, 0, 0, 0, 0, 0, 1.1, 0, 0, -50, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + "minlevel": 2, + "enabled": true + }, + { + "name":"stars_hardlight_02", + "minlevel": 2, + "enabled": true + }, + { + "name":"coffee_mpl", + "minlevel": 2, + "enabled": true + }, + { + "name":"security_hardlight", + "minlevel": 3, + "enabled": true + }, + { + "name":"bluemood_mpl", + "minlevel": 3, + "enabled": true + }, + { + "name":"rusty_mpl", + "minlevel": 3, + "enabled": true + }, + { + "name":"decr_conrast", + "colorMatrix": [0.5, 0, 0, 0, 50, 0, 0.5, 0, 0, 50, 0, 0, 0.5, 0, 50, 0, 0, 0, 1, 0], + "minlevel": 4, + "enabled": true + }, + { + "name":"green_2", + "colorMatrix": [0.5, 0.5, 0.5, 0, 0, 0.5, 0.5, 0.5, 0, 90, 0.5, 0.5, 0.5, 0, 0, 0, 0, 0, 1, 0], + "minlevel": 4, + "enabled": true + }, + { + "name":"alien_hrd", + "minlevel": 4, + "enabled": true + }, + { + "name":"color_3", + "colorMatrix": [0.609, 0.609, 0.082, 0, 0, 0.309, 0.609, 0.082, 0, 0, 0.309, 0.609, 0.082, 0, 0, 0, 0, 0, 1, 0], + "minlevel": 5, + "enabled": true + }, + { + "name":"color_4", + "colorMatrix": [0.8, -0.8, 1, 0, 70, 0.8, -0.8, 1, 0, 70, 0.8, -0.8, 1, 0, 70, 0, 0, 0, 1, 0], + "minlevel": 5, + "enabled": true + }, + { + "name":"toxic_hrd", + "minlevel": 5, + "enabled": true + }, + { + "name":"hypersaturated", + "colorMatrix": [2, -1, 0, 0, 0, -1, 2, 0, 0, 0, 0, -1, 2, 0, 0, 0, 0, 0, 1, 0], + "minlevel": 6, + "enabled": true + }, + { + "name":"Yellow", + "colorMatrix": [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + "minlevel": 6, + "enabled": true + }, + { + "name":"misty_hrd", + "minlevel": 6, + "enabled": true + }, + { + "name":"x_ray", + "colorMatrix": [0, 1.2, 0, 0, -100, 0, 2, 0, 0, -120, 0, 2, 0, 0, -120, 0, 0, 0, 1, 0], + "minlevel": 7, + "enabled": true + }, + { + "name":"decrease_saturation", + "colorMatrix": [0.7, 0.2, 0.2, 0, 0, 0.2, 0.7, 0.2, 0, 0, 0.2, 0.2, 0.7, 0, 0, 0, 0, 0, 1, 0], + "minlevel": 7, + "enabled": true + }, + { + "name":"drops_mpl", + "minlevel": 8, + "enabled": true + }, + { + "name":"shiny_hrd", + "minlevel": 9, + "enabled": true + }, + { + "name":"glitter_hrd", + "minlevel": 10, + "enabled": true + }, + { + "name":"frame_gold", + "minlevel": 10, + "enabled": true + }, + { + "name":"frame_gray_4", + "minlevel": 10, + "enabled": true + }, + { + "name":"frame_black_2", + "minlevel": 10, + "enabled": true + }, + { + "name":"frame_wood_2", + "minlevel": 10, + "enabled": true + }, + { + "name":"finger_nrm", + "minlevel": 10, + "enabled": true + }, + { + "name":"color_5", + "colorMatrix": [3.309, 0.609, 1.082, 0.2, 0, 0.309, 0.609, 0.082, 0, 0, 1.309, 0.609, 0.082, 0, 0, 0, 0, 0, 1, 0], + "minlevel": 10, + "enabled": true + }, + { + "name":"black_white_negative", + "colorMatrix": [-0.5, -0.5, -0.5, 0, 0, -0.5, -0.5, -0.5, 0, 0, -0.5, -0.5, -0.5, 0, 0, 0, 0, 0, 1, 0], + "minlevel": 10, + "enabled": true + }, + { + "name":"blue", + "colorMatrix": [0.5, 0.5, 0.5, 0, -255, 0.5, 0.5, 0.5, 0, -170, 0.5, 0.5, 0.5, 0, 0, 0, 0, 0, 1, 0], + "minlevel": 10, + "enabled": true + }, + { + "name":"red", + "colorMatrix": [0.5, 0.5, 0.5, 0, 0, 0.5, 0.5, 0.5, 0, -170, 0.5, 0.5, 0.5, 0, -170, 0, 0, 0, 1, 0], + "minlevel": 10, + "enabled": true + }, + { + "name":"green", + "colorMatrix": [0.5, 0.5, 0.5, 0, -170, 0.5, 0.5, 0.5, 0, 0, 0.5, 0.5, 0.5, 0, -170, 0, 0, 0, 1, 0], + "minlevel": 10, + "enabled": true + } + ], "avatar.default.figuredata": " DDDDDD FAFAFA EEEEEE FA3831 FD92A0 2AC7D2 35332C EFFF92 C6FF98 FF925A 9D597E B6F3FF 6DFF33 3378C9 FFB631 DFA1E9 F9FB32 CAAF8F C5C6C5 47623D 8A8361 FF8C33 54C627 1E6C99 984F88 77C8FF FFC08E 3C4B87 7C2C47 D7FFE3 8F3F1C FF6393 1F9B79 FDFF33 ", "avatar.default.actions": { "actions": [ diff --git a/src/assets/images/icons/camera-colormatrix.png b/src/assets/images/icons/camera-colormatrix.png new file mode 100644 index 00000000..894396e7 Binary files /dev/null and b/src/assets/images/icons/camera-colormatrix.png differ diff --git a/src/assets/images/icons/camera-composite.png b/src/assets/images/icons/camera-composite.png new file mode 100644 index 00000000..681fb18c Binary files /dev/null and b/src/assets/images/icons/camera-composite.png differ diff --git a/src/assets/images/room-widgets/camera-widget/camera-spritesheet.png b/src/assets/images/room-widgets/camera-widget/camera-spritesheet.png index 3d3f4184..f215f0c9 100644 Binary files a/src/assets/images/room-widgets/camera-widget/camera-spritesheet.png and b/src/assets/images/room-widgets/camera-widget/camera-spritesheet.png differ diff --git a/src/assets/images/room-widgets/camera-widget/selected.png b/src/assets/images/room-widgets/camera-widget/selected.png deleted file mode 100644 index 91a58b86..00000000 Binary files a/src/assets/images/room-widgets/camera-widget/selected.png and /dev/null differ diff --git a/src/assets/images/room-widgets/camera-widget/selector.png b/src/assets/images/room-widgets/camera-widget/selector.png deleted file mode 100644 index f49ac8b3..00000000 Binary files a/src/assets/images/room-widgets/camera-widget/selector.png and /dev/null differ diff --git a/src/assets/styles/icons.scss b/src/assets/styles/icons.scss index 112bc679..dc97caba 100644 --- a/src/assets/styles/icons.scss +++ b/src/assets/styles/icons.scss @@ -446,6 +446,18 @@ i { height: 20px; } + &.icon-camera-colormatrix { + background: url('../images/icons/camera-colormatrix.png'); + width: 32px; + height: 14px; + } + + &.icon-camera-composite { + background: url('../images/icons/camera-composite.png'); + width: 32px; + height: 14px; + } + &.spin { animation: rotating 1s linear infinite; } diff --git a/src/layout/card/content/NitroCardContentView.tsx b/src/layout/card/content/NitroCardContentView.tsx index a2f1ab40..5a5c8c65 100644 --- a/src/layout/card/content/NitroCardContentView.tsx +++ b/src/layout/card/content/NitroCardContentView.tsx @@ -1,13 +1,12 @@ -import classNames from 'classnames'; import { FC } from 'react'; import { NitroCardContentViewProps } from './NitroCardContextView.types'; export const NitroCardContentView: FC = props => { - const { isDark = false } = props; - + const { className = null } = props; + return ( -
+
{ props.children }
); diff --git a/src/layout/card/content/NitroCardContextView.types.ts b/src/layout/card/content/NitroCardContextView.types.ts index ae0dfc8a..78ff6979 100644 --- a/src/layout/card/content/NitroCardContextView.types.ts +++ b/src/layout/card/content/NitroCardContextView.types.ts @@ -1,4 +1,4 @@ export interface NitroCardContentViewProps { - isDark?: boolean; + className?: string; } diff --git a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx index 12d825da..61d859a0 100644 --- a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx +++ b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx @@ -34,7 +34,7 @@ export const AvatarInfoWidgetView: FC = props => return value; }); - return [ ...existing, new RoomObjectNameData(nameData.objectId, nameData.category, nameData.id, nameData.name, nameData.type) ] + return [ ...existing, nameData ] }); } return; diff --git a/src/views/room/widgets/camera/CameraWidgetView.scss b/src/views/room/widgets/camera/CameraWidgetView.scss index 4b7f8363..e24d2e21 100644 --- a/src/views/room/widgets/camera/CameraWidgetView.scss +++ b/src/views/room/widgets/camera/CameraWidgetView.scss @@ -1,29 +1,94 @@ -.nitro-camera { - width: 340px; - height: 462px; +.nitro-camera-capture { + .camera-canvas { + width: 340px; + height: 462px; + + background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png'); - background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png'); + .camera-frame { + position: absolute; + width: 318px; + height: 318px; + margin-top: 9px; + margin-left: 11.4px; - .camera-frame { - width: 300px; - height: 300px; + &.bg { + background: black; + } + + .camera-frame-preview-actions { + background: rgba(0, 0, 0, .5); + } + } + + .camera-button { + width: 94px; + height: 94px; + cursor: pointer; + margin-top: 334px; + + background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png'); + background-position: -340px 0px; + + &:hover { + background-position: -340px -94px; + } + + &:active { + background-position: -340px -188px; + } + } } - .camera-button { - width: 94px; - height: 94px; - cursor: pointer; - margin-top: 334px; + .camera-roll { + width: 330px; + background: #bab8b4; + border-bottom-left-radius: 10px; + border-bottom-right-radius: 10px; + border: 1px solid black; + box-shadow: inset 1px 0px white, inset -1px -1px white; - background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png'); - background-position: -340px 0px; - - &:hover { - background-position: -340px -94px; - } - - &:active { - background-position: -340px -188px; + img { + width: 56px; + height: 56px; + border: 1px solid black; + } + } +} + +.nitro-camera-editor { + width: 600px; + + .effects { + max-height: 354px; + + .effect-thumbnail { + border-color: $grid-border-color !important; + background-color: $grid-bg-color; + + &.active { + border-color: $grid-active-border-color !important; + background-color: $grid-active-bg-color; + } + + .effect-thumbnail-image { + background: black; + + img { + width: 56px; + height: 56px; + } + } + } + } + + .picture-preview { + width: 318px; + height: 318px; + + &.zoomed { + background-size: 636px; + background-position: center; } } } diff --git a/src/views/room/widgets/camera/CameraWidgetView.tsx b/src/views/room/widgets/camera/CameraWidgetView.tsx index 6b43ad2c..6e3a3ad3 100644 --- a/src/views/room/widgets/camera/CameraWidgetView.tsx +++ b/src/views/room/widgets/camera/CameraWidgetView.tsx @@ -1,72 +1,75 @@ -import { NitroRectangle } from 'nitro-renderer'; -import { FC, useCallback, useRef, useState } from 'react'; -import { GetRoomEngine, GetRoomSession } from '../../../../api'; +import { RoomCameraWidgetEditorEffect } from 'nitro-renderer/src/nitro/room/camera-widget/RoomCameraWidgetEditorEffect'; +import { RoomCameraWidgetManagerEvent } from 'nitro-renderer/src/nitro/room/events/RoomCameraWidgetManagerEvent'; +import { FC, useCallback, useState } from 'react'; +import { GetRoomEngine } from '../../../../api'; import { RoomWidgetCameraEvent } from '../../../../events/room-widgets/camera/RoomWidgetCameraEvent'; -import { DraggableWindow } from '../../../../hooks/draggable-window/DraggableWindow'; +import { useRoomEngineEvent } from '../../../../hooks/events/nitro/room/room-engine-event'; import { useUiEvent } from '../../../../hooks/events/ui/ui-event'; import { CameraWidgetViewProps } from './CameraWidgetView.types'; +import { CameraWidgetCaptureView } from './views/capture/CameraWidgetCaptureView'; +import { CameraWidgetEditorView } from './views/editor/CameraWidgetEditorView'; export const CameraWidgetView: FC = props => { - const [ isVisible, setIsVisible ] = useState(false); - const cameraFrameRef = useRef(); + const [ isCaptureVisible, setIsCaptureVisible ] = useState(false); + const [ isEditorVisible, setIsEditorVisible ] = useState(false); + const [ chosenPicture, setChosenPicture ] = useState(null); + const [ availableEffects, setAvailableEffects ] = useState(null); - const onRoomWidgetCameraEvent = useCallback((event: RoomWidgetCameraEvent) => + const getAvailableEffects = useCallback(() => + { + if(GetRoomEngine().roomCameraWidgetManager.isLoaded) + { + setAvailableEffects(Array.from(GetRoomEngine().roomCameraWidgetManager.loadedEffects.values())); + } + }, []); + + const onNitroEvent = useCallback((event: RoomWidgetCameraEvent) => { switch(event.type) { case RoomWidgetCameraEvent.SHOW_CAMERA: - setIsVisible(true); + setIsCaptureVisible(true); + getAvailableEffects(); return; case RoomWidgetCameraEvent.HIDE_CAMERA: - setIsVisible(false); + setIsCaptureVisible(false); + setIsEditorVisible(false); return; case RoomWidgetCameraEvent.TOGGLE_CAMERA: - setIsVisible(value => !value); + setIsEditorVisible(false); + setIsCaptureVisible(value => !value); + getAvailableEffects(); + return; + case RoomCameraWidgetManagerEvent.INITIALIZED: + getAvailableEffects(); return; } }, []); - useUiEvent(RoomWidgetCameraEvent.SHOW_CAMERA, onRoomWidgetCameraEvent); - useUiEvent(RoomWidgetCameraEvent.HIDE_CAMERA, onRoomWidgetCameraEvent); - useUiEvent(RoomWidgetCameraEvent.TOGGLE_CAMERA, onRoomWidgetCameraEvent); + useUiEvent(RoomWidgetCameraEvent.SHOW_CAMERA, onNitroEvent); + useUiEvent(RoomWidgetCameraEvent.HIDE_CAMERA, onNitroEvent); + useUiEvent(RoomWidgetCameraEvent.TOGGLE_CAMERA, onNitroEvent); + useRoomEngineEvent(RoomCameraWidgetManagerEvent.INITIALIZED, onNitroEvent); - const processAction = useCallback((type: string, value: string = null) => + const processAction = useCallback((type: string, value: any = null) => { switch(type) { case 'close': - setIsVisible(false); + setIsCaptureVisible(false); + setIsEditorVisible(false); + return; + case 'capture_choose_picture': + setChosenPicture(value); + setIsCaptureVisible(false); + setIsEditorVisible(true); return; } }, []); - const takePicture = useCallback(() => - { - const frameBounds = cameraFrameRef.current.getBoundingClientRect(); - - if(!frameBounds) return; - - const rectangle = new NitroRectangle(Math.floor(frameBounds.x), Math.floor(frameBounds.y), Math.floor(frameBounds.width), Math.floor(frameBounds.height)); - - GetRoomEngine().createRoomScreenshot(GetRoomSession().roomId, 1, rectangle); - }, []); - - if(!isVisible) return null; - return ( - -
-
-
processAction('close') }> - -
-
-
-
-
-
-
-
+ ( isCaptureVisible && processAction('close') } onChoosePicture={ (picture) => processAction('capture_choose_picture', picture) } /> ) || + ( isEditorVisible && processAction('close') } picture={ chosenPicture } availableEffects={ availableEffects } /> ) ); } diff --git a/src/views/room/widgets/camera/views/capture/CameraWidgetCaptureView.tsx b/src/views/room/widgets/camera/views/capture/CameraWidgetCaptureView.tsx new file mode 100644 index 00000000..e57f2626 --- /dev/null +++ b/src/views/room/widgets/camera/views/capture/CameraWidgetCaptureView.tsx @@ -0,0 +1,102 @@ +import classNames from 'classnames'; +import { NitroRectangle } from 'nitro-renderer'; +import { FC, useCallback, useRef, useState } from 'react'; +import { GetRoomEngine } from '../../../../../../api/nitro/room/GetRoomEngine'; +import { GetRoomSession } from '../../../../../../api/nitro/session/GetRoomSession'; +import { DraggableWindow } from '../../../../../../hooks/draggable-window/DraggableWindow'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import { CameraWidgetCaptureViewProps } from './CameraWidgetCaptureView.types'; + +export const CameraWidgetCaptureView: FC = props => +{ + const CAMERA_ROLL_LIMIT: number = 5; + + const [ picturesTaken, setPicturesTaken ] = useState([]); + const [ selectedPictureIndex, setSelectedPictureIndex ] = useState(-1); + const cameraFrameRef = useRef(); + + const takePicture = useCallback(() => + { + if(selectedPictureIndex > -1) + { + setSelectedPictureIndex(-1); + return; + } + + const frameBounds = cameraFrameRef.current.getBoundingClientRect(); + + if(!frameBounds) return; + + const rectangle = new NitroRectangle(Math.floor(frameBounds.x), Math.floor(frameBounds.y), Math.floor(frameBounds.width), Math.floor(frameBounds.height)); + + const image = GetRoomEngine().createRoomScreenshot(GetRoomSession().roomId, 1, rectangle); + + if(picturesTaken.length + 1 === CAMERA_ROLL_LIMIT) + { + alert(LocalizeText('camera.full.body')); + } + + if(picturesTaken.length === CAMERA_ROLL_LIMIT) + { + setPicturesTaken(picturesTaken => [ ...picturesTaken.slice(0, CAMERA_ROLL_LIMIT - 1), image ]); + } + else + { + setPicturesTaken(picturesTaken => [ ...picturesTaken, image ]); + } + }, [ picturesTaken, selectedPictureIndex ]); + + const processAction = useCallback((type: string, value: string | number = null) => + { + switch(type) + { + case 'take_picture': + takePicture(); + return; + case 'preview_picture': + setSelectedPictureIndex(Number(value)); + return; + case 'discard_picture': + setSelectedPictureIndex(-1); + const newPicturesTaken = picturesTaken; + picturesTaken.splice(selectedPictureIndex, 1); + setPicturesTaken(newPicturesTaken); + return; + case 'edit_picture': + props.onChoosePicture(picturesTaken[selectedPictureIndex]); + return; + } + }, [ picturesTaken, selectedPictureIndex ]); + + return ( + +
+
+
+
+ +
+
+
-1}) }> + { selectedPictureIndex > -1 &&
+ +
+ + +
+
} +
+
+
+
+
+ { picturesTaken.length > 0 &&
+ { picturesTaken.map((picture, index) => + { + return processAction('preview_picture', index) } />; + }) } +
} +
+
+ ); +} diff --git a/src/views/room/widgets/camera/views/capture/CameraWidgetCaptureView.types.ts b/src/views/room/widgets/camera/views/capture/CameraWidgetCaptureView.types.ts new file mode 100644 index 00000000..435e6d29 --- /dev/null +++ b/src/views/room/widgets/camera/views/capture/CameraWidgetCaptureView.types.ts @@ -0,0 +1,5 @@ +export interface CameraWidgetCaptureViewProps +{ + onCloseClick: () => void; + onChoosePicture: (picture: HTMLImageElement) => void; +} diff --git a/src/views/room/widgets/camera/views/editor/CameraWidgetEditorView.tsx b/src/views/room/widgets/camera/views/editor/CameraWidgetEditorView.tsx new file mode 100644 index 00000000..0153ced7 --- /dev/null +++ b/src/views/room/widgets/camera/views/editor/CameraWidgetEditorView.tsx @@ -0,0 +1,127 @@ +import classNames from 'classnames'; +import { RoomCameraWidgetEditorSelectedEffect } from 'nitro-renderer/src/nitro/room/camera-widget/RoomCameraWidgetEditorSelectedEffect'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { GetRoomEngine } from '../../../../../../api'; +import { NitroCardContentView } from '../../../../../../layout/card/content/NitroCardContentView'; +import { NitroCardHeaderView } from '../../../../../../layout/card/header/NitroCardHeaderView'; +import { NitroCardView } from '../../../../../../layout/card/NitroCardView'; +import { NitroCardTabsView } from '../../../../../../layout/card/tabs/NitroCardTabsView'; +import { NitroCardTabsItemView } from '../../../../../../layout/card/tabs/tabs-item/NitroCardTabsItemView'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import { CameraWidgetEditorTabs, CameraWidgetEditorViewProps } from './CameraWidgetEditorView.types'; + +export const CameraWidgetEditorView: FC = props => +{ + const TABS: string[] = [ CameraWidgetEditorTabs.COLORMATRIX, CameraWidgetEditorTabs.COMPOSITE ]; + const MY_LEVEL: number = 0; + + const [ currentTab, setCurrentTab ] = useState(CameraWidgetEditorTabs.COLORMATRIX); + const [ isZoomed, setIsZoomed ] = useState(false); + const [ selectedEffects, setSelectedEffects ] = useState([]); + const [ effectsThumbnails, setEffectThumbnails ] = useState<{name: string, image: HTMLImageElement}[]>([]); + + useEffect(() => + { + const thumbnails = []; + + for(const effect of props.availableEffects) + { + let alpha = 126; + + if(effect.colorMatrix.length > 0) alpha = 0.5; + + thumbnails.push({name: effect.name, image: GetRoomEngine().roomCameraWidgetManager.editImage(props.picture, [new RoomCameraWidgetEditorSelectedEffect(effect, alpha)])}); + } + + setEffectThumbnails(thumbnails); + }, [ props.availableEffects ]); + + const getEffectThumbnail = useCallback((effectName: string) => + { + const search = effectsThumbnails.find(thumbnail => thumbnail.name === effectName); + + if(search) return search.image.src; + + return null; + }, [ effectsThumbnails ]); + + const getEffectList = useCallback(() => + { + if(currentTab === CameraWidgetEditorTabs.COLORMATRIX) + { + return props.availableEffects.filter(effect => effect.colorMatrix.length > 0); + } + else + { + return props.availableEffects.filter(effect => effect.colorMatrix.length === 0); + } + }, [ currentTab, props.availableEffects ]); + + const processAction = useCallback((type: string, value: string | number = null) => + { + switch(type) + { + case 'close': + props.onCloseClick(); + return; + case 'change_tab': + setCurrentTab(String(value)); + return; + case 'zoom': + setIsZoomed(isZoomed => !isZoomed); + return; + } + }, []); + + return ( + + processAction('close') } /> +
+
+ + { TABS.map(tab => + { + return processAction('change_tab', tab) }> + }) } + + +
+
+ { getEffectList().map(effect => + { + return ( +
+
+
+ +
+
+
+ ); + }) } +
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ +
+ + +
+
+
+ ); +} diff --git a/src/views/room/widgets/camera/views/editor/CameraWidgetEditorView.types.ts b/src/views/room/widgets/camera/views/editor/CameraWidgetEditorView.types.ts new file mode 100644 index 00000000..4a3407c6 --- /dev/null +++ b/src/views/room/widgets/camera/views/editor/CameraWidgetEditorView.types.ts @@ -0,0 +1,14 @@ +import { RoomCameraWidgetEditorEffect } from '../../../../../../../../nitro-renderer/src/nitro/room/camera-widget/RoomCameraWidgetEditorEffect'; + +export interface CameraWidgetEditorViewProps +{ + onCloseClick: () => void; + picture: HTMLImageElement; + availableEffects: RoomCameraWidgetEditorEffect[]; +} + +export class CameraWidgetEditorTabs +{ + public static readonly COLORMATRIX: string = 'colormatrix'; + public static readonly COMPOSITE: string = 'composite'; +}