From 190eb741a45428f1f3ca00bab6994e94c6c853f8 Mon Sep 17 00:00:00 2001 From: Kirill Lakhov Date: Fri, 31 Jan 2025 15:13:54 +0300 Subject: [PATCH] added auto saving + gamma correction filter --- .../header/settings-modal/settings-modal.tsx | 153 ++++++++++-------- .../utils/fabric-wrapper/gamma-correciton.ts | 6 + cvat-ui/src/utils/image-processing.tsx | 5 + 3 files changed, 96 insertions(+), 68 deletions(-) diff --git a/cvat-ui/src/components/header/settings-modal/settings-modal.tsx b/cvat-ui/src/components/header/settings-modal/settings-modal.tsx index 4a870f970a1f..8d47bd1b99c2 100644 --- a/cvat-ui/src/components/header/settings-modal/settings-modal.tsx +++ b/cvat-ui/src/components/header/settings-modal/settings-modal.tsx @@ -5,14 +5,13 @@ import './styles.scss'; import _ from 'lodash'; -import React, { useCallback, useEffect } from 'react'; +import React, { useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import Tabs from 'antd/lib/tabs'; import Text from 'antd/lib/typography/Text'; import Modal from 'antd/lib/modal/Modal'; import Button from 'antd/lib/button'; import notification from 'antd/lib/notification'; -import Tooltip from 'antd/lib/tooltip'; import { PlayCircleOutlined, LaptopOutlined, BuildOutlined } from '@ant-design/icons'; import { setSettings } from 'actions/settings-actions'; @@ -22,12 +21,16 @@ import PlayerSettingsContainer from 'containers/header/settings-modal/player-set import ShortcutsSettingsContainer from 'containers/header/settings-modal/shortcuts-settings'; import { CombinedState } from 'reducers'; import { conflict, conflictDetector } from 'utils/conflict-detector'; +import { ImageFilter, ImageFilterAlias } from 'utils/image-processing'; +import GammaCorrection, { GammaFilterOptions } from 'utils/fabric-wrapper/gamma-correciton'; interface SettingsModalProps { visible: boolean; onClose(): void; } +const SAVE_SETTINGS_DELAY = 2000; + function SettingsModal(props: SettingsModalProps): JSX.Element { const { visible, onClose } = props; @@ -35,38 +38,49 @@ function SettingsModal(props: SettingsModalProps): JSX.Element { const shortcuts = useSelector((state: CombinedState) => state.shortcuts); const dispatch = useDispatch(); - const onSaveSettings = useCallback(() => { - const settingsForSaving: any = { - shortcuts: { - keyMap: {}, - }, - }; - for (const [key, value] of Object.entries(settings)) { - if (['player', 'workspace'].includes(key)) { - settingsForSaving[key] = value; + useEffect(() => { + const handler = setTimeout(() => { + const settingsForSaving: any = { + shortcuts: { + keyMap: {}, + }, + imageFilters: [], + }; + for (const [key, value] of Object.entries(settings)) { + if (['player', 'workspace'].includes(key)) { + settingsForSaving[key] = value; + } + if (key === 'imageFilters') { + const filters = []; + for (const filter of value) { + filters.push({ + alias: filter.alias, + params: filter.modifier.serialize(), + }); + } + settingsForSaving.imageFilters = filters; + } } - } - for (const [key] of Object.entries(shortcuts.keyMap)) { - if (key in shortcuts.defaultState) { - settingsForSaving.shortcuts.keyMap[key] = { - sequences: shortcuts.keyMap[key].sequences, - }; + for (const [key] of Object.entries(shortcuts.keyMap)) { + if (key in shortcuts.defaultState) { + settingsForSaving.shortcuts.keyMap[key] = { + sequences: shortcuts.keyMap[key].sequences, + }; + } } - } - localStorage.setItem('clientSettings', JSON.stringify(settingsForSaving)); - notification.success({ - message: 'Settings were successfully saved', - className: 'cvat-notification-notice-save-settings-success', - }); + localStorage.setItem('clientSettings', JSON.stringify(settingsForSaving)); + }, SAVE_SETTINGS_DELAY); - onClose(); - }, [onClose, settings, shortcuts]); + return () => { + clearTimeout(handler); + }; + }, [settings, shortcuts]); useEffect(() => { try { dispatch(shortcutsActions.setDefaultShortcuts(structuredClone(shortcuts.keyMap))); - const newSettings = _.pick(settings, 'player', 'workspace'); + const newSettings = { ..._.pick(settings, 'player', 'workspace'), imageFilters: [] as ImageFilter[] }; const settingsString = localStorage.getItem('clientSettings') as string; if (!settingsString) return; const loadedSettings = JSON.parse(settingsString); @@ -79,6 +93,26 @@ function SettingsModal(props: SettingsModalProps): JSX.Element { } } } + + newSettings.imageFilters = []; + if ('imageFilters' in loadedSettings) { + for (const filter of loadedSettings.imageFilters) { + switch (filter.alias) { + case ImageFilterAlias.GAMMA_CORRECTION: { + const modifier = new GammaCorrection(filter.params as GammaFilterOptions); + newSettings.imageFilters.push({ + modifier, + alias: ImageFilterAlias.GAMMA_CORRECTION, + }); + break; + } + default: { + break; + } + } + } + } + dispatch(setSettings(newSettings)); if ('shortcuts' in loadedSettings) { const updateKeyMap = structuredClone(shortcuts.keyMap); @@ -119,6 +153,27 @@ function SettingsModal(props: SettingsModalProps): JSX.Element { } }, []); + const tabItems = [ + { + key: 'player', + label: Player, + icon: , + children: , + }, + { + key: 'workspace', + label: Workspace, + icon: , + children: , + }, + { + key: 'shortcuts', + label: Shortcuts, + icon: , + children: , + }, + ]; + return ( - - - - - + )} >
- - - Player - - ), - children: , - }, { - key: 'workspace', - label: ( - - - Workspace - - ), - children: , - }, { - key: 'shortcuts', - label: ( - - - Shortcuts - - ), - children: , - }]} - /> +
); diff --git a/cvat-ui/src/utils/fabric-wrapper/gamma-correciton.ts b/cvat-ui/src/utils/fabric-wrapper/gamma-correciton.ts index 1d6d138df95b..8e19c432c254 100644 --- a/cvat-ui/src/utils/fabric-wrapper/gamma-correciton.ts +++ b/cvat-ui/src/utils/fabric-wrapper/gamma-correciton.ts @@ -34,6 +34,12 @@ export default class GammaCorrection extends FabricFilter { this.#gamma = newGamma; } + public serialize(): GammaFilterOptions { + return { + gamma: this.#gamma, + }; + } + get gamma(): number { return this.#gamma[0]; } diff --git a/cvat-ui/src/utils/image-processing.tsx b/cvat-ui/src/utils/image-processing.tsx index 6e652ccba13d..8f8e162ee85d 100644 --- a/cvat-ui/src/utils/image-processing.tsx +++ b/cvat-ui/src/utils/image-processing.tsx @@ -11,6 +11,7 @@ export interface ImageProcessing { processImage: (src: ImageData, frameNumber: number) => ImageData; configure: (options: object) => void; + serialize: () => any; } /* eslint @typescript-eslint/no-unused-vars: ["error", { "argsIgnorePattern": "^_" }] */ @@ -23,6 +24,10 @@ export class BaseImageFilter implements ImageProcessing { } configure(_options: object): void {} + + serialize(): any { + return {}; + } } export interface ImageFilter {