diff --git a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx index 74cd0bec..8a1b2781 100644 --- a/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx +++ b/cvat-ui/src/components/annotation-page/attribute-annotation-workspace/attribute-annotation-sidebar/attribute-annotation-sidebar.tsx @@ -32,6 +32,7 @@ interface StateToProps { states: any[]; labels: any[]; jobInstance: any; + keyMap: KeyMap; } interface DispatchToProps { @@ -56,6 +57,9 @@ function mapStateToProps(state: CombinedState): StateToProps { labels, }, }, + shortcuts: { + keyMap, + }, } = state; return { @@ -64,6 +68,7 @@ function mapStateToProps(state: CombinedState): StateToProps { activatedStateID, activatedAttributeID, states, + keyMap, }; } @@ -87,6 +92,7 @@ function AttributeAnnotationSidebar(props: StateToProps & DispatchToProps): JSX. jobInstance, updateAnnotations, activateObject, + keyMap, } = props; const [labelAttrMap, setLabelAttrMap] = useState( @@ -167,31 +173,11 @@ function AttributeAnnotationSidebar(props: StateToProps & DispatchToProps): JSX. trigger: null, }; - const keyMap = { - NEXT_ATTRIBUTE: { - name: 'Next attribute', - description: 'Go to the next attribute', - sequence: 'ArrowDown', - action: 'keydown', - }, - PREVIOUS_ATTRIBUTE: { - name: 'Previous attribute', - description: 'Go to the previous attribute', - sequence: 'ArrowUp', - action: 'keydown', - }, - NEXT_OBJECT: { - name: 'Next object', - description: 'Go to the next object', - sequence: 'Tab', - action: 'keydown', - }, - PREVIOUS_OBJECT: { - name: 'Previous object', - description: 'Go to the previous object', - sequence: 'Shift+Tab', - action: 'keydown', - }, + const subKeyMap = { + NEXT_ATTRIBUTE: keyMap.NEXT_ATTRIBUTE, + PREVIOUS_ATTRIBUTE: keyMap.PREVIOUS_ATTRIBUTE, + NEXT_OBJECT: keyMap.NEXT_OBJECT, + PREVIOUS_OBJECT: keyMap.PREVIOUS_OBJECT, }; const handlers = { @@ -228,7 +214,7 @@ function AttributeAnnotationSidebar(props: StateToProps & DispatchToProps): JSX. if (activeObjectState) { return ( - + diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx index 4cf77599..ee2af8d8 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx @@ -59,6 +59,7 @@ interface Props { contextType: ContextMenuType; aamZoomMargin: number; workspace: Workspace; + keyMap: KeyMap; onSetupCanvas: () => void; onDragCanvas: (enabled: boolean) => void; onZoomCanvas: (enabled: boolean) => void; @@ -683,6 +684,7 @@ export default class CanvasWrapperComponent extends React.PureComponent { onChangeGridColor, onChangeGridOpacity, onSwitchGrid, + keyMap, } = this.props; const preventDefault = (event: KeyboardEvent | undefined): void => { @@ -691,61 +693,16 @@ export default class CanvasWrapperComponent extends React.PureComponent { } }; - const keyMap = { - INCREASE_BRIGHTNESS: { - name: 'Brightness+', - description: 'Increase brightness level for the image', - sequence: 'shift+b+=', - action: 'keypress', - }, - DECREASE_BRIGHTNESS: { - name: 'Brightness-', - description: 'Decrease brightness level for the image', - sequence: 'shift+b+-', - action: 'keydown', - }, - INCREASE_CONTRAST: { - name: 'Contrast+', - description: 'Increase contrast level for the image', - sequence: 'shift+c+=', - action: 'keydown', - }, - DECREASE_CONTRAST: { - name: 'Contrast-', - description: 'Decrease contrast level for the image', - sequence: 'shift+c+-', - action: 'keydown', - }, - INCREASE_SATURATION: { - name: 'Saturation+', - description: 'Increase saturation level for the image', - sequence: 'shift+s+=', - action: 'keydown', - }, - DECREASE_SATURATION: { - name: 'Saturation-', - description: 'Increase contrast level for the image', - sequence: 'shift+s+-', - action: 'keydown', - }, - INCREASE_GRID_OPACITY: { - name: 'Grid opacity+', - description: 'Make the grid more visible', - sequence: 'shift+g+=', - action: 'keydown', - }, - DECREASE_GRID_OPACITY: { - name: 'Grid opacity-', - description: 'Make the grid less visible', - sequences: 'shift+g+-', - action: 'keydown', - }, - CHANGE_GRID_COLOR: { - name: 'Grid color', - description: 'Set another color for the image grid', - sequence: 'shift+g+enter', - action: 'keydown', - }, + const subKeyMap = { + INCREASE_BRIGHTNESS: keyMap.INCREASE_BRIGHTNESS, + DECREASE_BRIGHTNESS: keyMap.DECREASE_BRIGHTNESS, + INCREASE_CONTRAST: keyMap.INCREASE_CONTRAST, + DECREASE_CONTRAST: keyMap.DECREASE_CONTRAST, + INCREASE_SATURATION: keyMap.INCREASE_SATURATION, + DECREASE_SATURATION: keyMap.DECREASE_SATURATION, + INCREASE_GRID_OPACITY: keyMap.INCREASE_GRID_OPACITY, + DECREASE_GRID_OPACITY: keyMap.DECREASE_GRID_OPACITY, + CHANGE_GRID_COLOR: keyMap.CHANGE_GRID_COLOR, }; const step = 10; @@ -826,7 +783,7 @@ export default class CanvasWrapperComponent extends React.PureComponent { return ( - + {/* This element doesn't have any props So, React isn't going to rerender it diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/controls-side-bar.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/controls-side-bar.tsx index bf151997..18a1b3b2 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/controls-side-bar.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/controls-side-bar.tsx @@ -35,6 +35,7 @@ import SplitControl from './split-control'; interface Props { canvasInstance: Canvas; activeControl: ActiveControl; + keyMap: KeyMap; mergeObjects(enabled: boolean): void; groupObjects(enabled: boolean): void; @@ -57,6 +58,7 @@ export default function ControlsSideBarComponent(props: Props): JSX.Element { repeatDrawShape, pasteShape, resetGroup, + keyMap, } = props; const preventDefault = (event: KeyboardEvent | undefined): void => { @@ -65,55 +67,15 @@ export default function ControlsSideBarComponent(props: Props): JSX.Element { } }; - const keyMap = { - PASTE_SHAPE: { - name: 'Paste shape', - description: 'Paste a shape from internal CVAT clipboard', - sequence: 'ctrl+v', - action: 'keydown', - }, - SWITCH_DRAW_MODE: { - name: 'Draw mode', - description: 'Repeat the latest procedure of drawing with the same parameters', - sequence: 'n', - action: 'keydown', - }, - SWITCH_MERGE_MODE: { - name: 'Merge mode', - description: 'Activate or deactivate mode to merging shapes', - sequence: 'm', - action: 'keydown', - }, - SWITCH_GROUP_MODE: { - name: 'Group mode', - description: 'Activate or deactivate mode to grouping shapes', - sequence: 'g', - action: 'keydown', - }, - RESET_GROUP: { - name: 'Reset group', - description: 'Reset group for selected shapes (in group mode)', - sequence: 'shift+g', - action: 'keyup', - }, - CANCEL: { - name: 'Cancel', - description: 'Cancel any active canvas mode', - sequence: 'esc', - action: 'keydown', - }, - CLOCKWISE_ROTATION: { - name: 'Rotate clockwise', - description: 'Change image angle (add 90 degrees)', - sequence: 'ctrl+r', - action: 'keydown', - }, - ANTICLOCKWISE_ROTATION: { - name: 'Rotate anticlockwise', - description: 'Change image angle (substract 90 degrees)', - sequence: 'ctrl+shift+r', - action: 'keydown', - }, + const subKeyMap = { + PASTE_SHAPE: keyMap.PASTE_SHAPE, + SWITCH_DRAW_MODE: keyMap.SWITCH_DRAW_MODE, + SWITCH_MERGE_MODE: keyMap.SWITCH_MERGE_MODE, + SWITCH_GROUP_MODE: keyMap.SWITCH_GROUP_MODE, + RESET_GROUP: keyMap.RESET_GROUP, + CANCEL: keyMap.CANCEL, + CLOCKWISE_ROTATION: keyMap.CLOCKWISE_ROTATION, + ANTICLOCKWISE_ROTATION: keyMap.ANTICLOCKWISE_ROTATION, }; const handlers = { @@ -186,7 +148,7 @@ export default function ControlsSideBarComponent(props: Props): JSX.Element { theme='light' width={44} > - + diff --git a/cvat-ui/src/components/cvat-app.tsx b/cvat-ui/src/components/cvat-app.tsx index 0bfc29c5..6c5d24cb 100644 --- a/cvat-ui/src/components/cvat-app.tsx +++ b/cvat-ui/src/components/cvat-app.tsx @@ -37,6 +37,7 @@ interface CVATAppProps { resetErrors: () => void; resetMessages: () => void; switchShortcutsDialog: () => void; + keyMap: KeyMap; userInitialized: boolean; userFetching: boolean; pluginsInitialized: boolean; @@ -209,6 +210,7 @@ class CVATApplication extends React.PureComponent - + diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/canvas-wrapper.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/canvas-wrapper.tsx index 75845dc8..ffc20a27 100644 --- a/cvat-ui/src/containers/annotation-page/standard-workspace/canvas-wrapper.tsx +++ b/cvat-ui/src/containers/annotation-page/standard-workspace/canvas-wrapper.tsx @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: MIT +import { KeyMap } from 'react-hotkeys'; import { connect } from 'react-redux'; import CanvasWrapperComponent from 'components/annotation-page/standard-workspace/canvas-wrapper'; @@ -78,6 +79,7 @@ interface StateToProps { curZLayer: number; contextVisible: boolean; contextType: ContextMenuType; + keyMap: KeyMap; } interface DispatchToProps { @@ -169,6 +171,9 @@ function mapStateToProps(state: CombinedState): StateToProps { blackBorders, }, }, + shortcuts: { + keyMap, + }, } = state; return { @@ -204,6 +209,7 @@ function mapStateToProps(state: CombinedState): StateToProps { contextVisible, contextType, workspace, + keyMap, }; } diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/controls-side-bar.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/controls-side-bar.tsx index 1f0b1f31..16292cd9 100644 --- a/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/controls-side-bar.tsx +++ b/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/controls-side-bar.tsx @@ -2,10 +2,10 @@ // // SPDX-License-Identifier: MIT +import { KeyMap } from 'react-hotkeys'; import { connect } from 'react-redux'; import { Canvas } from 'cvat-canvas'; - import { mergeObjects, groupObjects, @@ -16,16 +16,13 @@ import { resetAnnotationsGroup, } from 'actions/annotation-actions'; import ControlsSideBarComponent from 'components/annotation-page/standard-workspace/controls-side-bar/controls-side-bar'; -import { - ActiveControl, - CombinedState, - Rotation, -} from 'reducers/interfaces'; +import { ActiveControl, CombinedState, Rotation } from 'reducers/interfaces'; interface StateToProps { canvasInstance: Canvas; rotateAll: boolean; activeControl: ActiveControl; + keyMap: KeyMap; } interface DispatchToProps { @@ -51,12 +48,16 @@ function mapStateToProps(state: CombinedState): StateToProps { rotateAll, }, }, + shortcuts: { + keyMap, + }, } = state; return { rotateAll, canvasInstance, activeControl, + keyMap, }; } diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx index b7a18933..d51ec34e 100644 --- a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx +++ b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/object-item.tsx @@ -7,11 +7,7 @@ import copy from 'copy-to-clipboard'; import { connect } from 'react-redux'; import { LogType } from 'cvat-logger'; -import { - ActiveControl, - CombinedState, - ColorBy, -} from 'reducers/interfaces'; +import { ActiveControl, CombinedState, ColorBy } from 'reducers/interfaces'; import { collapseObjectItems, changeLabelColorAsync, @@ -411,7 +407,7 @@ class ObjectItemContainer extends React.PureComponent { private changeAttribute = (id: number, value: string): void => { const { objectState, jobInstance } = this.props; jobInstance.logger.log(LogType.changeAttribute, { - id, + id, value, object_id: objectState.clientID, }); diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/objects-list.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/objects-list.tsx index 5279620f..98b5a844 100644 --- a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/objects-list.tsx +++ b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/objects-list.tsx @@ -16,11 +16,7 @@ import { propagateObject as propagateObjectAction, } from 'actions/annotation-actions'; -import { - CombinedState, - StatesOrdering, - ObjectType, -} from 'reducers/interfaces'; +import { CombinedState, StatesOrdering, ObjectType } from 'reducers/interfaces'; interface StateToProps { jobInstance: any; @@ -35,6 +31,7 @@ interface StateToProps { minZLayer: number; maxZLayer: number; annotationsFiltersHistory: string[]; + keyMap: KeyMap; } interface DispatchToProps { @@ -70,6 +67,9 @@ function mapStateToProps(state: CombinedState): StateToProps { }, tabContentHeight: listHeight, }, + shortcuts: { + keyMap, + }, } = state; let statesHidden = true; @@ -101,6 +101,7 @@ function mapStateToProps(state: CombinedState): StateToProps { minZLayer, maxZLayer, annotationsFiltersHistory, + keyMap, }; } @@ -249,97 +250,28 @@ class ObjectsListContainer extends React.PureComponent { changeFrame, maxZLayer, minZLayer, + keyMap, } = this.props; const { sortedStatesID, statesOrdering, } = this.state; - const keyMap = { - SWITCH_ALL_LOCK: { - name: 'Lock/unlock all objects', - description: 'Change locked state for all objects in the side bar', - sequence: 't+l', - action: 'keydown', - }, - SWITCH_LOCK: { - name: 'Lock/unlock an object', - description: 'Change locked state for an active object', - sequence: 'l', - action: 'keydown', - }, - SWITCH_ALL_HIDDEN: { - name: 'Hide/show all objects', - description: 'Change hidden state for objects in the side bar', - sequence: 't+h', - action: 'keydown', - }, - SWITCH_HIDDEN: { - name: 'Hide/show an object', - description: 'Change hidden state for an active object', - sequence: 'h', - action: 'keydown', - }, - SWITCH_OCCLUDED: { - name: 'Switch occluded', - description: 'Change occluded property for an active object', - sequences: ['q', '/'], - action: 'keydown', - }, - SWITCH_KEYFRAME: { - name: 'Switch keyframe', - description: 'Change keyframe property for an active track', - sequence: 'k', - action: 'keydown', - }, - SWITCH_OUTSIDE: { - name: 'Switch outside', - description: 'Change outside property for an active track', - sequence: 'o', - action: 'keydown', - }, - DELETE_OBJECT: { - name: 'Delete object', - description: 'Delete an active object. Use shift to force delete of locked objects', - sequences: ['del', 'shift+del'], - action: 'keydown', - }, - TO_BACKGROUND: { - name: 'To background', - description: 'Put an active object "farther" from the user (decrease z axis value)', - sequences: ['-', '_'], - action: 'keydown', - }, - TO_FOREGROUND: { - name: 'To foreground', - description: 'Put an active object "closer" to the user (increase z axis value)', - sequences: ['+', '='], - action: 'keydown', - }, - COPY_SHAPE: { - name: 'Copy shape', - description: 'Copy shape to CVAT internal clipboard', - sequence: 'ctrl+c', - action: 'keydown', - }, - PROPAGATE_OBJECT: { - name: 'Propagate object', - description: 'Make a copy of the object on the following frames', - sequence: 'ctrl+b', - action: 'keydown', - }, - NEXT_KEY_FRAME: { - name: 'Next keyframe', - description: 'Go to the next keyframe of an active track', - sequence: 'r', - action: 'keydown', - }, - PREV_KEY_FRAME: { - name: 'Previous keyframe', - description: 'Go to the previous keyframe of an active track', - sequence: 'e', - action: 'keydown', - }, + const subKeyMap = { + SWITCH_ALL_LOCK: keyMap.SWITCH_ALL_LOCK, + SWITCH_LOCK: keyMap.SWITCH_LOCK, + SWITCH_ALL_HIDDEN: keyMap.SWITCH_ALL_HIDDEN, + SWITCH_HIDDEN: keyMap.SWITCH_HIDDEN, + SWITCH_OCCLUDED: keyMap.SWITCH_OCCLUDED, + SWITCH_KEYFRAME: keyMap.SWITCH_KEYFRAME, + SWITCH_OUTSIDE: keyMap.SWITCH_OUTSIDE, + DELETE_OBJECT: keyMap.DELETE_OBJECT, + TO_BACKGROUND: keyMap.TO_BACKGROUND, + TO_FOREGROUND: keyMap.TO_FOREGROUND, + COPY_SHAPE: keyMap.COPY_SHAPE, + PROPAGATE_OBJECT: keyMap.PROPAGATE_OBJECT, + NEXT_KEY_FRAME: keyMap.NEXT_KEY_FRAME, + PREV_KEY_FRAME: keyMap.PREV_KEY_FRAME, }; const preventDefault = (event: KeyboardEvent | undefined): void => { @@ -473,7 +405,7 @@ class ObjectsListContainer extends React.PureComponent { return ( <> - + { canvasIsReady, searchAnnotations, changeWorkspace, + keyMap, } = this.props; const preventDefault = (event: KeyboardEvent | undefined): void => { @@ -472,73 +478,18 @@ class AnnotationTopBarContainer extends React.PureComponent { } }; - const keyMap = { - SAVE_JOB: { - name: 'Save the job', - description: 'Send all changes of annotations to the server', - sequence: 'ctrl+s', - action: 'keydown', - }, - UNDO: { - name: 'Undo action', - description: 'Cancel the latest action related with objects', - sequence: 'ctrl+z', - action: 'keydown', - }, - REDO: { - name: 'Redo action', - description: 'Cancel undo action', - sequences: ['ctrl+shift+z', 'ctrl+y'], - action: 'keydown', - }, - NEXT_FRAME: { - name: 'Next frame', - description: 'Go to the next frame', - sequence: 'f', - action: 'keydown', - }, - PREV_FRAME: { - name: 'Previous frame', - description: 'Go to the previous frame', - sequence: 'd', - action: 'keydown', - }, - FORWARD_FRAME: { - name: 'Forward frame', - description: 'Go forward with a step', - sequence: 'v', - action: 'keydown', - }, - BACKWARD_FRAME: { - name: 'Backward frame', - description: 'Go backward with a step', - sequence: 'c', - action: 'keydown', - }, - SEARCH_FORWARD: { - name: 'Search forward', - description: 'Search the next frame that satisfies to the filters', - sequence: 'right', - action: 'keydown', - }, - SEARCH_BACKWARD: { - name: 'Search backward', - description: 'Search the previous frame that satisfies to the filters', - sequence: 'left', - action: 'keydown', - }, - PLAY_PAUSE: { - name: 'Play/pause', - description: 'Start/stop automatic changing frames', - sequence: 'space', - action: 'keydown', - }, - FOCUS_INPUT_FRAME: { - name: 'Focus input frame', - description: 'Focus on the element to change the current frame', - sequences: ['`', '~'], - action: 'keydown', - }, + const subKeyMap = { + SAVE_JOB: keyMap.SAVE_JOB, + UNDO: keyMap.UNDO, + REDO: keyMap.REDO, + NEXT_FRAME: keyMap.SAVE_JOB, + PREV_FRAME: keyMap.PREV_FRAME, + FORWARD_FRAME: keyMap.FORWARD_FRAME, + BACKWARD_FRAME: keyMap.BACKWARD_FRAME, + SEARCH_FORWARD: keyMap.SEARCH_FORWARD, + SEARCH_BACKWARD: keyMap.SEARCH_BACKWARD, + PLAY_PAUSE: keyMap.PLAY_PAUSE, + FOCUS_INPUT_FRAME: keyMap.FOCUS_INPUT_FRAME, }; const handlers = { @@ -608,7 +559,7 @@ class AnnotationTopBarContainer extends React.PureComponent { return ( <> - +