Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added hotkeys to change labels #3070

Merged
merged 12 commits into from
Apr 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [1.4.0] - Unreleased

### Added

- Documentation on mask annotation (<https://github.com/openvinotoolkit/cvat/pull/3044>)
- Hotkeys to switch a label of existing object or to change default label (for objects created with N) (<https://github.com/openvinotoolkit/cvat/pull/3070>)

### Changed

-

### Deprecated

-

### Removed

-

### Fixed

- Export of instance masks with holes (<https://github.com/openvinotoolkit/cvat/pull/3044>)

### Security
-

-

## [1.3.0] - 3/31/2021

Expand Down
2 changes: 1 addition & 1 deletion cvat-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cvat-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.18.1",
"version": "1.19.0",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
Expand Down
36 changes: 8 additions & 28 deletions cvat-ui/src/actions/annotation-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1130,36 +1130,16 @@ export function saveAnnotationsAsync(sessionInstance: any, afterSave?: () => voi
}

// used to reproduce the latest drawing (in case of tags just creating) by using N
export function rememberObject(
objectType: ObjectType,
labelID: number,
shapeType?: ShapeType,
points?: number,
rectDrawingMethod?: RectDrawingMethod,
): AnyAction {
let activeControl = ActiveControl.CURSOR;
if (shapeType === ShapeType.RECTANGLE) {
activeControl = ActiveControl.DRAW_RECTANGLE;
} else if (shapeType === ShapeType.POLYGON) {
activeControl = ActiveControl.DRAW_POLYGON;
} else if (shapeType === ShapeType.POLYLINE) {
activeControl = ActiveControl.DRAW_POLYLINE;
} else if (shapeType === ShapeType.POINTS) {
activeControl = ActiveControl.DRAW_POINTS;
} else if (shapeType === ShapeType.CUBOID) {
activeControl = ActiveControl.DRAW_CUBOID;
}

export function rememberObject(createParams: {
activeObjectType?: ObjectType;
activeLabelID?: number;
activeShapeType?: ShapeType;
activeNumOfPoints?: number;
activeRectDrawingMethod?: RectDrawingMethod;
}): AnyAction {
return {
type: AnnotationActionTypes.REMEMBER_CREATED_OBJECT,
payload: {
shapeType,
labelID,
objectType,
points,
activeControl,
rectDrawingMethod,
},
payload: createParams,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { CombinedState } from 'reducers/interfaces';
import {
LeftOutlined, RightOutlined, EyeInvisibleFilled, EyeOutlined,
} from '@ant-design/icons';
Expand All @@ -14,6 +13,7 @@ import { Row, Col } from 'antd/lib/grid';
import { changeFrameAsync } from 'actions/annotation-actions';
import { reviewActions } from 'actions/review-actions';
import CVATTooltip from 'components/common/cvat-tooltip';
import { CombinedState } from 'reducers/interfaces';

export default function LabelsListComponent(): JSX.Element {
const dispatch = useDispatch();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2020 Intel Corporation
// Copyright (C) 2020-2021 Intel Corporation
//
// SPDX-License-Identifier: MIT

Expand All @@ -10,31 +10,45 @@ import {
LockFilled, UnlockOutlined, EyeInvisibleFilled, EyeOutlined,
} from '@ant-design/icons';

import CVATTooltip from 'components/common/cvat-tooltip';
import LabelKeySelectorPopover from './label-key-selector-popover';

interface Props {
labelName: string;
labelColor: string;
labelID: number;
visible: boolean;
statesHidden: boolean;
statesLocked: boolean;
keyToLabelMapping: Record<string, number>;
hideStates(): void;
showStates(): void;
lockStates(): void;
unlockStates(): void;
updateLabelShortcutKey(updatedKey: string, labelID: number): void;
}

function LabelItemComponent(props: Props): JSX.Element {
const {
labelName,
labelColor,
labelID,
keyToLabelMapping,
visible,
statesHidden,
statesLocked,
hideStates,
showStates,
lockStates,
unlockStates,
updateLabelShortcutKey,
} = props;

// create reversed mapping just to receive key easily
const labelToKeyMapping: Record<string, string> = Object.fromEntries(
Object.entries(keyToLabelMapping).map(([key, _labelID]) => [_labelID, key]),
);
const labelShortcutKey = labelToKeyMapping[labelID] || '?';
const classes = {
lock: {
enabled: { className: 'cvat-label-item-button-lock cvat-label-item-button-lock-enabled' },
Expand All @@ -48,22 +62,37 @@ function LabelItemComponent(props: Props): JSX.Element {

return (
<Row
align='middle'
align='stretch'
justify='space-around'
className='cvat-objects-sidebar-label-item'
style={{ display: visible ? 'flex' : 'none' }}
className={[
'cvat-objects-sidebar-label-item',
visible ? '' : 'cvat-objects-sidebar-label-item-disabled',
].join(' ')}
>
<Col span={4}>
<Button style={{ background: labelColor }} className='cvat-label-item-color-button'>
<Col span={2}>
<div style={{ background: labelColor }} className='cvat-label-item-color'>
{' '}
</Button>
</div>
</Col>
<Col span={14}>
<Text strong className='cvat-text'>
{labelName}
</Text>
<Col span={12}>
<CVATTooltip title={labelName}>
<Text strong className='cvat-text'>
{labelName}
</Text>
</CVATTooltip>
</Col>
<Col span={3}>
<LabelKeySelectorPopover
keyToLabelMapping={keyToLabelMapping}
labelID={labelID}
updateLabelShortcutKey={updateLabelShortcutKey}
>
<Button className='cvat-label-item-setup-shortcut-button' size='small' ghost type='dashed'>
{labelShortcutKey}
</Button>
</LabelKeySelectorPopover>
</Col>
<Col span={2} offset={1}>
{statesLocked ? (
<LockFilled {...classes.lock.enabled} onClick={unlockStates} />
) : (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright (C) 2021 Intel Corporation
//
// SPDX-License-Identifier: MIT

import React from 'react';
import { useSelector } from 'react-redux';
import Popover from 'antd/lib/popover';
import Button from 'antd/lib/button';
import { Row, Col } from 'antd/lib/grid';
import Text from 'antd/lib/typography/Text';

import { CombinedState } from 'reducers/interfaces';
import CVATTooltip from 'components/common/cvat-tooltip';

interface LabelKeySelectorPopoverProps {
updateLabelShortcutKey(updatedKey: string, labelID: number): void;
keyToLabelMapping: Record<string, number>;
labelID: number;
children: JSX.Element;
}

interface LabelKeySelectorPopoverContentProps {
updateLabelShortcutKey(updatedKey: string, labelID: number): void;
labelID: number;
keyToLabelMapping: Record<string, number>;
}

function PopoverContent(props: LabelKeySelectorPopoverContentProps): JSX.Element {
const { keyToLabelMapping, labelID, updateLabelShortcutKey } = props;
const labels = useSelector((state: CombinedState) => state.annotation.job.labels);

return (
<div className='cvat-label-item-setup-shortcut-popover'>
{[['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9'], ['0']].map((arr, i_) => (
<Row justify='space-around' gutter={[16, 16]} key={i_}>
{arr.map((i) => {
const previousLabelID = keyToLabelMapping[i];
const labelName = Number.isInteger(previousLabelID) ?
labels.filter((label: any): boolean => label.id === previousLabelID)[0]?.name ||
'undefined' :
'None';

return (
<Col key={i} span={8}>
<CVATTooltip title={labelName}>
<Button onClick={() => updateLabelShortcutKey(i, labelID)}>
<Text>{`${i}:`}</Text>
<Text type='secondary'>{labelName}</Text>
</Button>
</CVATTooltip>
</Col>
);
})}
</Row>
))}
</div>
);
}

const MemoizedContent = React.memo(PopoverContent);

function LabelKeySelectorPopover(props: LabelKeySelectorPopoverProps): JSX.Element {
const {
children, labelID, updateLabelShortcutKey, keyToLabelMapping,
} = props;

return (
<Popover
destroyTooltipOnHide={{ keepParent: false }}
trigger='click'
content={(
<MemoizedContent
keyToLabelMapping={keyToLabelMapping}
labelID={labelID}
updateLabelShortcutKey={updateLabelShortcutKey}
/>
)}
placement='left'
>
{children}
</Popover>
);
}

export default React.memo(LabelKeySelectorPopover);
Loading