mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-23 14:40:50 +01:00
Merge branch 'dev' of https://github.com/billsonnn/nitro-react into dev
This commit is contained in:
commit
4d5915fa98
File diff suppressed because one or more lines are too long
BIN
src/assets/images/icons/camera-colormatrix.png
Normal file
BIN
src/assets/images/icons/camera-colormatrix.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 249 B |
BIN
src/assets/images/icons/camera-composite.png
Normal file
BIN
src/assets/images/icons/camera-composite.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 204 B |
Binary file not shown.
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 183 B |
Binary file not shown.
Before Width: | Height: | Size: 154 B |
@ -446,6 +446,18 @@ i {
|
|||||||
height: 20px;
|
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 {
|
&.spin {
|
||||||
animation: rotating 1s linear infinite;
|
animation: rotating 1s linear infinite;
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import classNames from 'classnames';
|
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { NitroCardContentViewProps } from './NitroCardContextView.types';
|
import { NitroCardContentViewProps } from './NitroCardContextView.types';
|
||||||
|
|
||||||
export const NitroCardContentView: FC<NitroCardContentViewProps> = props =>
|
export const NitroCardContentView: FC<NitroCardContentViewProps> = props =>
|
||||||
{
|
{
|
||||||
const { isDark = false } = props;
|
const { className = null } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={ 'container-fluid bg-light content-area ' + classNames({ 'bg-light': !isDark, 'bg-dark': isDark }) }>
|
<div className={ 'container-fluid bg-light content-area ' + className }>
|
||||||
{ props.children }
|
{ props.children }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export interface NitroCardContentViewProps
|
export interface NitroCardContentViewProps
|
||||||
{
|
{
|
||||||
isDark?: boolean;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ export const AvatarInfoWidgetView: FC<AvatarInfoWidgetViewProps> = props =>
|
|||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
|
|
||||||
return [ ...existing, new RoomObjectNameData(nameData.objectId, nameData.category, nameData.id, nameData.name, nameData.type) ]
|
return [ ...existing, nameData ]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -1,29 +1,94 @@
|
|||||||
.nitro-camera {
|
.nitro-camera-capture {
|
||||||
width: 340px;
|
.camera-canvas {
|
||||||
height: 462px;
|
width: 340px;
|
||||||
|
height: 462px;
|
||||||
background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
|
|
||||||
|
|
||||||
.camera-frame {
|
|
||||||
width: 300px;
|
|
||||||
height: 300px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.camera-button {
|
|
||||||
width: 94px;
|
|
||||||
height: 94px;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-top: 334px;
|
|
||||||
|
|
||||||
background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
|
background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
|
||||||
background-position: -340px 0px;
|
|
||||||
|
|
||||||
&:hover {
|
.camera-frame {
|
||||||
background-position: -340px -94px;
|
position: absolute;
|
||||||
|
width: 318px;
|
||||||
|
height: 318px;
|
||||||
|
margin-top: 9px;
|
||||||
|
margin-left: 11.4px;
|
||||||
|
|
||||||
|
&.bg {
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.camera-frame-preview-actions {
|
||||||
|
background: rgba(0, 0, 0, .5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:active {
|
.camera-button {
|
||||||
background-position: -340px -188px;
|
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-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;
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,72 +1,75 @@
|
|||||||
import { NitroRectangle } from 'nitro-renderer';
|
import { RoomCameraWidgetEditorEffect } from 'nitro-renderer/src/nitro/room/camera-widget/RoomCameraWidgetEditorEffect';
|
||||||
import { FC, useCallback, useRef, useState } from 'react';
|
import { RoomCameraWidgetManagerEvent } from 'nitro-renderer/src/nitro/room/events/RoomCameraWidgetManagerEvent';
|
||||||
import { GetRoomEngine, GetRoomSession } from '../../../../api';
|
import { FC, useCallback, useState } from 'react';
|
||||||
|
import { GetRoomEngine } from '../../../../api';
|
||||||
import { RoomWidgetCameraEvent } from '../../../../events/room-widgets/camera/RoomWidgetCameraEvent';
|
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 { useUiEvent } from '../../../../hooks/events/ui/ui-event';
|
||||||
import { CameraWidgetViewProps } from './CameraWidgetView.types';
|
import { CameraWidgetViewProps } from './CameraWidgetView.types';
|
||||||
|
import { CameraWidgetCaptureView } from './views/capture/CameraWidgetCaptureView';
|
||||||
|
import { CameraWidgetEditorView } from './views/editor/CameraWidgetEditorView';
|
||||||
|
|
||||||
export const CameraWidgetView: FC<CameraWidgetViewProps> = props =>
|
export const CameraWidgetView: FC<CameraWidgetViewProps> = props =>
|
||||||
{
|
{
|
||||||
const [ isVisible, setIsVisible ] = useState(false);
|
const [ isCaptureVisible, setIsCaptureVisible ] = useState(false);
|
||||||
const cameraFrameRef = useRef<HTMLDivElement>();
|
const [ isEditorVisible, setIsEditorVisible ] = useState(false);
|
||||||
|
const [ chosenPicture, setChosenPicture ] = useState<HTMLImageElement>(null);
|
||||||
|
const [ availableEffects, setAvailableEffects ] = useState<RoomCameraWidgetEditorEffect[]>(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)
|
switch(event.type)
|
||||||
{
|
{
|
||||||
case RoomWidgetCameraEvent.SHOW_CAMERA:
|
case RoomWidgetCameraEvent.SHOW_CAMERA:
|
||||||
setIsVisible(true);
|
setIsCaptureVisible(true);
|
||||||
|
getAvailableEffects();
|
||||||
return;
|
return;
|
||||||
case RoomWidgetCameraEvent.HIDE_CAMERA:
|
case RoomWidgetCameraEvent.HIDE_CAMERA:
|
||||||
setIsVisible(false);
|
setIsCaptureVisible(false);
|
||||||
|
setIsEditorVisible(false);
|
||||||
return;
|
return;
|
||||||
case RoomWidgetCameraEvent.TOGGLE_CAMERA:
|
case RoomWidgetCameraEvent.TOGGLE_CAMERA:
|
||||||
setIsVisible(value => !value);
|
setIsEditorVisible(false);
|
||||||
|
setIsCaptureVisible(value => !value);
|
||||||
|
getAvailableEffects();
|
||||||
|
return;
|
||||||
|
case RoomCameraWidgetManagerEvent.INITIALIZED:
|
||||||
|
getAvailableEffects();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useUiEvent(RoomWidgetCameraEvent.SHOW_CAMERA, onRoomWidgetCameraEvent);
|
useUiEvent(RoomWidgetCameraEvent.SHOW_CAMERA, onNitroEvent);
|
||||||
useUiEvent(RoomWidgetCameraEvent.HIDE_CAMERA, onRoomWidgetCameraEvent);
|
useUiEvent(RoomWidgetCameraEvent.HIDE_CAMERA, onNitroEvent);
|
||||||
useUiEvent(RoomWidgetCameraEvent.TOGGLE_CAMERA, onRoomWidgetCameraEvent);
|
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)
|
switch(type)
|
||||||
{
|
{
|
||||||
case 'close':
|
case 'close':
|
||||||
setIsVisible(false);
|
setIsCaptureVisible(false);
|
||||||
|
setIsEditorVisible(false);
|
||||||
|
return;
|
||||||
|
case 'capture_choose_picture':
|
||||||
|
setChosenPicture(value);
|
||||||
|
setIsCaptureVisible(false);
|
||||||
|
setIsEditorVisible(true);
|
||||||
return;
|
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 (
|
return (
|
||||||
<DraggableWindow handle=".nitro-camera">
|
( isCaptureVisible && <CameraWidgetCaptureView onCloseClick={ () => processAction('close') } onChoosePicture={ (picture) => processAction('capture_choose_picture', picture) } /> ) ||
|
||||||
<div className="nitro-camera">
|
( isEditorVisible && <CameraWidgetEditorView onCloseClick={ () => processAction('close') } picture={ chosenPicture } availableEffects={ availableEffects } /> )
|
||||||
<div className="overflow-auto">
|
|
||||||
<div className="cursor-pointer float-end me-3 mt-2" onClick={ event => processAction('close') }>
|
|
||||||
<i className="fas fa-times"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="d-flex justify-content-center">
|
|
||||||
<div ref={ cameraFrameRef } className="camera-frame"></div>
|
|
||||||
<div className="camera-button" onClick={ takePicture }></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</DraggableWindow>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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<CameraWidgetCaptureViewProps> = props =>
|
||||||
|
{
|
||||||
|
const CAMERA_ROLL_LIMIT: number = 5;
|
||||||
|
|
||||||
|
const [ picturesTaken, setPicturesTaken ] = useState<HTMLImageElement[]>([]);
|
||||||
|
const [ selectedPictureIndex, setSelectedPictureIndex ] = useState(-1);
|
||||||
|
const cameraFrameRef = useRef<HTMLDivElement>();
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<DraggableWindow handle=".nitro-camera-capture">
|
||||||
|
<div className="nitro-camera-capture d-flex flex-column justify-content-center align-items-center">
|
||||||
|
<div className="camera-canvas">
|
||||||
|
<div className="overflow-auto">
|
||||||
|
<div className="cursor-pointer float-end me-3 mt-2" onClick={ props.onCloseClick }>
|
||||||
|
<i className="fas fa-times"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ref={ cameraFrameRef } className={'camera-frame ' + classNames({'bg': selectedPictureIndex > -1}) }>
|
||||||
|
{ selectedPictureIndex > -1 && <div>
|
||||||
|
<img src={ picturesTaken[selectedPictureIndex].src } />
|
||||||
|
<div className="camera-frame-preview-actions w-100 position-absolute bottom-0 py-2 text-center">
|
||||||
|
<button className="btn btn-success me-3" onClick={ event => processAction('edit_picture') }>{ LocalizeText('camera.editor.button.text') }</button>
|
||||||
|
<button className="btn btn-danger" onClick={ event => processAction('discard_picture') }>{ LocalizeText('camera.delete.button.text') }</button>
|
||||||
|
</div>
|
||||||
|
</div> }
|
||||||
|
</div>
|
||||||
|
<div className="d-flex justify-content-center">
|
||||||
|
<div className="camera-button" onClick={ takePicture }></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{ picturesTaken.length > 0 && <div className="camera-roll d-flex justify-content-center py-2">
|
||||||
|
{ picturesTaken.map((picture, index) =>
|
||||||
|
{
|
||||||
|
return <img key={ index } className={ (index < picturesTaken.length - 1 ? 'me-2' : '') } src={ picture.src } onClick={ event => processAction('preview_picture', index) } />;
|
||||||
|
}) }
|
||||||
|
</div> }
|
||||||
|
</div>
|
||||||
|
</DraggableWindow>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
export interface CameraWidgetCaptureViewProps
|
||||||
|
{
|
||||||
|
onCloseClick: () => void;
|
||||||
|
onChoosePicture: (picture: HTMLImageElement) => void;
|
||||||
|
}
|
@ -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<CameraWidgetEditorViewProps> = 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<RoomCameraWidgetEditorSelectedEffect[]>([]);
|
||||||
|
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 (
|
||||||
|
<NitroCardView className="nitro-camera-editor">
|
||||||
|
<NitroCardHeaderView headerText={ LocalizeText('camera.editor.button.text') } onCloseClick={ event => processAction('close') } />
|
||||||
|
<div className="d-flex">
|
||||||
|
<div className="w-100">
|
||||||
|
<NitroCardTabsView>
|
||||||
|
{ TABS.map(tab =>
|
||||||
|
{
|
||||||
|
return <NitroCardTabsItemView key={ tab } isActive={ currentTab === tab } onClick={ event => processAction('change_tab', tab) }><i className={ 'icon icon-camera-' + tab }></i></NitroCardTabsItemView>
|
||||||
|
}) }
|
||||||
|
</NitroCardTabsView>
|
||||||
|
<NitroCardContentView>
|
||||||
|
<div className="d-flex h-100 overflow-auto effects px-2">
|
||||||
|
<div className="row row-cols-3">
|
||||||
|
{ getEffectList().map(effect =>
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<div key={ effect.name } className="col mb-3">
|
||||||
|
<div title={ LocalizeText('camera.effect.name.' + effect.name) } className="effect-thumbnail cursor-pointer position-relative border border-2 rounded d-flex flex-column justify-content-center align-items-center py-1">
|
||||||
|
<div className="effect-thumbnail-image rounded">
|
||||||
|
<img className="rounded" src={ getEffectThumbnail(effect.name) } />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}) }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</NitroCardContentView>
|
||||||
|
</div>
|
||||||
|
<div className="w-100">
|
||||||
|
<NitroCardTabsView></NitroCardTabsView>
|
||||||
|
<NitroCardContentView>
|
||||||
|
<div className="bg-black rounded">
|
||||||
|
<div className={ 'picture-preview rounded' + classNames({ ' zoomed': isZoomed }) } style={ { backgroundImage: 'url(' + props.picture.src + ')' } }></div>
|
||||||
|
</div>
|
||||||
|
<div className="d-flex mt-2">
|
||||||
|
<button className="btn btn-primary btn-sm me-2">{ LocalizeText('save') }</button>
|
||||||
|
<button className="btn btn-primary btn-sm" onClick={ event => processAction('zoom') }>{ LocalizeText('room.zoom.button.text') }</button>
|
||||||
|
</div>
|
||||||
|
</NitroCardContentView>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<NitroCardContentView>
|
||||||
|
<div className="d-flex justify-content-end">
|
||||||
|
<button className="btn btn-primary me-2">{ LocalizeText('generic.cancel') }</button>
|
||||||
|
<button className="btn btn-success">{ LocalizeText('camera.preview.button.text') }</button>
|
||||||
|
</div>
|
||||||
|
</NitroCardContentView>
|
||||||
|
</NitroCardView>
|
||||||
|
);
|
||||||
|
}
|
@ -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';
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user