Migration to mousetrap, redesigned visualization settings (#2872)
* Initial version of shortcut fixes using mousetrap * Redesigned visualization settings * Updated cypress tests * Minor fix in AAM * Aborted extra changes * 1.1.0 * Updated version & changelog * Aborted extra changes * Fixed headers * Using keycodes in cypress * Fixed a couple of commandsmain
parent
dff57eb24b
commit
fb17dca505
@ -0,0 +1,189 @@
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import React from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Row, Col } from 'antd/lib/grid';
|
||||
import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox';
|
||||
import Text from 'antd/lib/typography/Text';
|
||||
import InputNumber from 'antd/lib/input-number';
|
||||
import Select from 'antd/lib/select';
|
||||
import Slider from 'antd/lib/slider';
|
||||
import Button from 'antd/lib/button';
|
||||
|
||||
import {
|
||||
switchGrid,
|
||||
changeGridColor,
|
||||
changeGridOpacity,
|
||||
changeBrightnessLevel,
|
||||
changeContrastLevel,
|
||||
changeSaturationLevel,
|
||||
changeGridSize,
|
||||
} from 'actions/settings-actions';
|
||||
import { clamp } from 'utils/math';
|
||||
import { GridColor, CombinedState, PlayerSettingsState } from 'reducers/interfaces';
|
||||
|
||||
const minGridSize = 5;
|
||||
const maxGridSize = 1000;
|
||||
|
||||
export default function ImageSetupsContent(): JSX.Element {
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
brightnessLevel,
|
||||
contrastLevel,
|
||||
saturationLevel,
|
||||
gridOpacity,
|
||||
gridColor,
|
||||
gridSize,
|
||||
grid: gridEnabled,
|
||||
} = useSelector((state: CombinedState): PlayerSettingsState => state.settings.player);
|
||||
|
||||
return (
|
||||
<div className='cvat-canvas-image-setups-content'>
|
||||
<Text>Image grid</Text>
|
||||
<hr />
|
||||
<Row justify='space-between' align='middle' gutter={8}>
|
||||
<Col span={1} />
|
||||
<Col span={6}>
|
||||
<Text className='cvat-text-color'> Size </Text>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Text className='cvat-text-color'> Color </Text>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Text className='cvat-text-color'> Opacity </Text>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row justify='space-between' align='middle' gutter={8}>
|
||||
<Col span={1}>
|
||||
<Checkbox
|
||||
className='cvat-text-color cvat-image-setups-grid'
|
||||
checked={gridEnabled}
|
||||
onChange={(event: CheckboxChangeEvent): void => {
|
||||
dispatch(switchGrid(event.target.checked));
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={6} className='cvat-image-setups-grid-size'>
|
||||
<InputNumber
|
||||
className='cvat-image-setups-grid-size-input'
|
||||
min={minGridSize}
|
||||
max={maxGridSize}
|
||||
value={gridSize}
|
||||
disabled={!gridEnabled}
|
||||
onChange={(value: number | undefined | null | string): void => {
|
||||
if (typeof value !== 'undefined' && value !== null) {
|
||||
const converted = Math.floor(clamp(+value, minGridSize, maxGridSize));
|
||||
dispatch(changeGridSize(converted));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={8} className='cvat-image-setups-grid-color'>
|
||||
<Select
|
||||
className='cvat-image-setups-grid-color-input'
|
||||
value={gridColor}
|
||||
disabled={!gridEnabled}
|
||||
onChange={(color: GridColor): void => {
|
||||
dispatch(changeGridColor(color));
|
||||
}}
|
||||
>
|
||||
<Select.Option key='white' value={GridColor.White}>
|
||||
White
|
||||
</Select.Option>
|
||||
<Select.Option key='black' value={GridColor.Black}>
|
||||
Black
|
||||
</Select.Option>
|
||||
<Select.Option key='red' value={GridColor.Red}>
|
||||
Red
|
||||
</Select.Option>
|
||||
<Select.Option key='green' value={GridColor.Green}>
|
||||
Green
|
||||
</Select.Option>
|
||||
<Select.Option key='blue' value={GridColor.Blue}>
|
||||
Blue
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={8} className='cvat-image-setups-grid-opacity'>
|
||||
<Slider
|
||||
className='cvat-image-setups-grid-opacity-input'
|
||||
min={0}
|
||||
max={100}
|
||||
value={gridOpacity}
|
||||
disabled={!gridEnabled}
|
||||
onChange={(value: number | [number, number]): void => {
|
||||
dispatch(changeGridOpacity(value as number));
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Text>Color settings</Text>
|
||||
<hr />
|
||||
<Row justify='space-around'>
|
||||
<Col span={24}>
|
||||
<Row className='cvat-image-setups-brightness'>
|
||||
<Col span={6}>
|
||||
<Text className='cvat-text-color'> Brightness </Text>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Slider
|
||||
min={50}
|
||||
max={200}
|
||||
value={brightnessLevel}
|
||||
onChange={(value: number | [number, number]): void => {
|
||||
dispatch(changeBrightnessLevel(value as number));
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className='cvat-image-setups-contrast'>
|
||||
<Col span={6}>
|
||||
<Text className='cvat-text-color'> Contrast </Text>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Slider
|
||||
min={50}
|
||||
max={200}
|
||||
value={contrastLevel}
|
||||
onChange={(value: number | [number, number]): void => {
|
||||
dispatch(changeContrastLevel(value as number));
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className='cvat-image-setups-saturation'>
|
||||
<Col span={6}>
|
||||
<Text className='cvat-text-color'> Saturation </Text>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Slider
|
||||
min={0}
|
||||
max={300}
|
||||
value={saturationLevel}
|
||||
onChange={(value: number | [number, number]): void => {
|
||||
dispatch(changeSaturationLevel(value as number));
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className='cvat-image-setups-reset-color-settings' justify='space-around'>
|
||||
<Col>
|
||||
<Button
|
||||
onClick={() => {
|
||||
const defaultValue = 100;
|
||||
dispatch(changeBrightnessLevel(defaultValue));
|
||||
dispatch(changeContrastLevel(defaultValue));
|
||||
dispatch(changeSaturationLevel(defaultValue));
|
||||
}}
|
||||
>
|
||||
Reset color settings
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import Mousetrap from 'mousetrap';
|
||||
|
||||
export interface KeyMapItem {
|
||||
name: string;
|
||||
description: string;
|
||||
sequences: string[];
|
||||
action: 'keydown' | 'keyup' | 'keypress';
|
||||
}
|
||||
|
||||
export interface KeyMap {
|
||||
[index: string]: KeyMapItem;
|
||||
}
|
||||
|
||||
export interface Handlers {
|
||||
[index: string]: (event: KeyboardEvent) => void;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
children?: JSX.Element;
|
||||
keyMap: KeyMap;
|
||||
handlers: Handlers;
|
||||
}
|
||||
|
||||
const applicationKeyMap: KeyMap = {};
|
||||
|
||||
export default function GlobalHotKeys(props: Props): JSX.Element {
|
||||
const { children, keyMap, handlers } = props;
|
||||
useEffect(() => {
|
||||
for (const key of Object.keys(keyMap)) {
|
||||
const { sequences, action } = keyMap[key];
|
||||
const handler = handlers[key];
|
||||
Mousetrap.bind(sequences, handler, action);
|
||||
applicationKeyMap[key] = keyMap[key];
|
||||
}
|
||||
|
||||
return () => {
|
||||
for (const key of Object.keys(keyMap)) {
|
||||
const { sequences, action } = keyMap[key];
|
||||
Mousetrap.unbind(sequences, action);
|
||||
delete applicationKeyMap[key];
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
return children || <></>;
|
||||
}
|
||||
|
||||
export function getApplicationKeyMap(): KeyMap {
|
||||
return {
|
||||
...applicationKeyMap,
|
||||
};
|
||||
}
|
||||
Loading…
Reference in New Issue