[CVAT-UI]: Appearance settings in AAM, keyframe navigation and other buttons in AAM (#1820)
parent
76280be4ad
commit
757f0ade17
@ -0,0 +1,214 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import React, { Dispatch } from 'react';
|
||||||
|
import { AnyAction } from 'redux';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import Text from 'antd/lib/typography/Text';
|
||||||
|
import Radio, { RadioChangeEvent } from 'antd/lib/radio';
|
||||||
|
import Slider, { SliderValue } from 'antd/lib/slider';
|
||||||
|
import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox';
|
||||||
|
import Collapse from 'antd/lib/collapse';
|
||||||
|
|
||||||
|
import { ColorBy, CombinedState } from 'reducers/interfaces';
|
||||||
|
import {
|
||||||
|
collapseAppearance as collapseAppearanceAction,
|
||||||
|
updateTabContentHeight as updateTabContentHeightAction,
|
||||||
|
} from 'actions/annotation-actions';
|
||||||
|
import {
|
||||||
|
changeShapesColorBy as changeShapesColorByAction,
|
||||||
|
changeShapesOpacity as changeShapesOpacityAction,
|
||||||
|
changeSelectedShapesOpacity as changeSelectedShapesOpacityAction,
|
||||||
|
changeShapesBlackBorders as changeShapesBlackBordersAction,
|
||||||
|
changeShowBitmap as changeShowBitmapAction,
|
||||||
|
changeShowProjections as changeShowProjectionsAction,
|
||||||
|
} from 'actions/settings-actions';
|
||||||
|
|
||||||
|
interface StateToProps {
|
||||||
|
appearanceCollapsed: boolean;
|
||||||
|
colorBy: ColorBy;
|
||||||
|
opacity: number;
|
||||||
|
selectedOpacity: number;
|
||||||
|
blackBorders: boolean;
|
||||||
|
showBitmap: boolean;
|
||||||
|
showProjections: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DispatchToProps {
|
||||||
|
collapseAppearance(): void;
|
||||||
|
changeShapesColorBy(event: RadioChangeEvent): void;
|
||||||
|
changeShapesOpacity(event: SliderValue): void;
|
||||||
|
changeSelectedShapesOpacity(event: SliderValue): void;
|
||||||
|
changeShapesBlackBorders(event: CheckboxChangeEvent): void;
|
||||||
|
changeShowBitmap(event: CheckboxChangeEvent): void;
|
||||||
|
changeShowProjections(event: CheckboxChangeEvent): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function computeHeight(): number {
|
||||||
|
const [sidebar] = window.document.getElementsByClassName('cvat-objects-sidebar');
|
||||||
|
const [appearance] = window.document.getElementsByClassName('cvat-objects-appearance-collapse');
|
||||||
|
const [tabs] = Array.from(
|
||||||
|
window.document.querySelectorAll('.cvat-objects-sidebar-tabs > .ant-tabs-card-bar'),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sidebar && appearance && tabs) {
|
||||||
|
const maxHeight = sidebar ? sidebar.clientHeight : 0;
|
||||||
|
const appearanceHeight = appearance ? appearance.clientHeight : 0;
|
||||||
|
const tabsHeight = tabs ? tabs.clientHeight : 0;
|
||||||
|
return maxHeight - appearanceHeight - tabsHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps(state: CombinedState): StateToProps {
|
||||||
|
const {
|
||||||
|
annotation: {
|
||||||
|
appearanceCollapsed,
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
shapes: {
|
||||||
|
colorBy,
|
||||||
|
opacity,
|
||||||
|
selectedOpacity,
|
||||||
|
blackBorders,
|
||||||
|
showBitmap,
|
||||||
|
showProjections,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
return {
|
||||||
|
appearanceCollapsed,
|
||||||
|
colorBy,
|
||||||
|
opacity,
|
||||||
|
selectedOpacity,
|
||||||
|
blackBorders,
|
||||||
|
showBitmap,
|
||||||
|
showProjections,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function mapDispatchToProps(dispatch: Dispatch<AnyAction>): DispatchToProps {
|
||||||
|
return {
|
||||||
|
collapseAppearance(): void {
|
||||||
|
dispatch(collapseAppearanceAction());
|
||||||
|
const [collapser] = window.document
|
||||||
|
.getElementsByClassName('cvat-objects-appearance-collapse');
|
||||||
|
|
||||||
|
if (collapser) {
|
||||||
|
const listener = (event: Event): void => {
|
||||||
|
if ((event as TransitionEvent).propertyName === 'height') {
|
||||||
|
const height = computeHeight();
|
||||||
|
dispatch(updateTabContentHeightAction(height));
|
||||||
|
collapser.removeEventListener('transitionend', listener);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
collapser.addEventListener('transitionend', listener);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
changeShapesColorBy(event: RadioChangeEvent): void {
|
||||||
|
dispatch(changeShapesColorByAction(event.target.value));
|
||||||
|
},
|
||||||
|
changeShapesOpacity(value: SliderValue): void {
|
||||||
|
dispatch(changeShapesOpacityAction(value as number));
|
||||||
|
},
|
||||||
|
changeSelectedShapesOpacity(value: SliderValue): void {
|
||||||
|
dispatch(changeSelectedShapesOpacityAction(value as number));
|
||||||
|
},
|
||||||
|
changeShapesBlackBorders(event: CheckboxChangeEvent): void {
|
||||||
|
dispatch(changeShapesBlackBordersAction(event.target.checked));
|
||||||
|
},
|
||||||
|
changeShowBitmap(event: CheckboxChangeEvent): void {
|
||||||
|
dispatch(changeShowBitmapAction(event.target.checked));
|
||||||
|
},
|
||||||
|
changeShowProjections(event: CheckboxChangeEvent): void {
|
||||||
|
dispatch(changeShowProjectionsAction(event.target.checked));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = StateToProps & DispatchToProps;
|
||||||
|
|
||||||
|
function AppearanceBlock(props: Props): JSX.Element {
|
||||||
|
const {
|
||||||
|
appearanceCollapsed,
|
||||||
|
colorBy,
|
||||||
|
opacity,
|
||||||
|
selectedOpacity,
|
||||||
|
blackBorders,
|
||||||
|
showBitmap,
|
||||||
|
showProjections,
|
||||||
|
collapseAppearance,
|
||||||
|
changeShapesColorBy,
|
||||||
|
changeShapesOpacity,
|
||||||
|
changeSelectedShapesOpacity,
|
||||||
|
changeShapesBlackBorders,
|
||||||
|
changeShowBitmap,
|
||||||
|
changeShowProjections,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Collapse
|
||||||
|
onChange={collapseAppearance}
|
||||||
|
activeKey={appearanceCollapsed ? [] : ['appearance']}
|
||||||
|
className='cvat-objects-appearance-collapse'
|
||||||
|
>
|
||||||
|
<Collapse.Panel
|
||||||
|
header={
|
||||||
|
<Text strong>Appearance</Text>
|
||||||
|
}
|
||||||
|
key='appearance'
|
||||||
|
>
|
||||||
|
<div className='cvat-objects-appearance-content'>
|
||||||
|
<Text type='secondary'>Color by</Text>
|
||||||
|
<Radio.Group value={colorBy} onChange={changeShapesColorBy}>
|
||||||
|
<Radio.Button value={ColorBy.INSTANCE}>{ColorBy.INSTANCE}</Radio.Button>
|
||||||
|
<Radio.Button value={ColorBy.GROUP}>{ColorBy.GROUP}</Radio.Button>
|
||||||
|
<Radio.Button value={ColorBy.LABEL}>{ColorBy.LABEL}</Radio.Button>
|
||||||
|
</Radio.Group>
|
||||||
|
<Text type='secondary'>Opacity</Text>
|
||||||
|
<Slider
|
||||||
|
onChange={changeShapesOpacity}
|
||||||
|
value={opacity}
|
||||||
|
min={0}
|
||||||
|
max={100}
|
||||||
|
/>
|
||||||
|
<Text type='secondary'>Selected opacity</Text>
|
||||||
|
<Slider
|
||||||
|
onChange={changeSelectedShapesOpacity}
|
||||||
|
value={selectedOpacity}
|
||||||
|
min={0}
|
||||||
|
max={100}
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
onChange={changeShapesBlackBorders}
|
||||||
|
checked={blackBorders}
|
||||||
|
>
|
||||||
|
Black borders
|
||||||
|
</Checkbox>
|
||||||
|
<Checkbox
|
||||||
|
onChange={changeShowBitmap}
|
||||||
|
checked={showBitmap}
|
||||||
|
>
|
||||||
|
Show bitmap
|
||||||
|
</Checkbox>
|
||||||
|
<Checkbox
|
||||||
|
onChange={changeShowProjections}
|
||||||
|
checked={showProjections}
|
||||||
|
>
|
||||||
|
Show projections
|
||||||
|
</Checkbox>
|
||||||
|
</div>
|
||||||
|
</Collapse.Panel>
|
||||||
|
</Collapse>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps,
|
||||||
|
)(React.memo(AppearanceBlock));
|
||||||
@ -1,107 +0,0 @@
|
|||||||
// Copyright (C) 2020 Intel Corporation
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import Text from 'antd/lib/typography/Text';
|
|
||||||
import Radio, { RadioChangeEvent } from 'antd/lib/radio';
|
|
||||||
import Slider, { SliderValue } from 'antd/lib/slider';
|
|
||||||
import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox';
|
|
||||||
import Collapse from 'antd/lib/collapse';
|
|
||||||
|
|
||||||
import { ColorBy } from 'reducers/interfaces';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
appearanceCollapsed: boolean;
|
|
||||||
colorBy: ColorBy;
|
|
||||||
opacity: number;
|
|
||||||
selectedOpacity: number;
|
|
||||||
blackBorders: boolean;
|
|
||||||
showBitmap: boolean;
|
|
||||||
showProjections: boolean;
|
|
||||||
|
|
||||||
collapseAppearance(): void;
|
|
||||||
changeShapesColorBy(event: RadioChangeEvent): void;
|
|
||||||
changeShapesOpacity(event: SliderValue): void;
|
|
||||||
changeSelectedShapesOpacity(event: SliderValue): void;
|
|
||||||
changeShapesBlackBorders(event: CheckboxChangeEvent): void;
|
|
||||||
changeShowBitmap(event: CheckboxChangeEvent): void;
|
|
||||||
changeShowProjections(event: CheckboxChangeEvent): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
function AppearanceBlock(props: Props): JSX.Element {
|
|
||||||
const {
|
|
||||||
appearanceCollapsed,
|
|
||||||
colorBy,
|
|
||||||
opacity,
|
|
||||||
selectedOpacity,
|
|
||||||
blackBorders,
|
|
||||||
showBitmap,
|
|
||||||
showProjections,
|
|
||||||
collapseAppearance,
|
|
||||||
changeShapesColorBy,
|
|
||||||
changeShapesOpacity,
|
|
||||||
changeSelectedShapesOpacity,
|
|
||||||
changeShapesBlackBorders,
|
|
||||||
changeShowBitmap,
|
|
||||||
changeShowProjections,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Collapse
|
|
||||||
onChange={collapseAppearance}
|
|
||||||
activeKey={appearanceCollapsed ? [] : ['appearance']}
|
|
||||||
className='cvat-objects-appearance-collapse'
|
|
||||||
>
|
|
||||||
<Collapse.Panel
|
|
||||||
header={
|
|
||||||
<Text strong>Appearance</Text>
|
|
||||||
}
|
|
||||||
key='appearance'
|
|
||||||
>
|
|
||||||
<div className='cvat-objects-appearance-content'>
|
|
||||||
<Text type='secondary'>Color by</Text>
|
|
||||||
<Radio.Group value={colorBy} onChange={changeShapesColorBy}>
|
|
||||||
<Radio.Button value={ColorBy.INSTANCE}>{ColorBy.INSTANCE}</Radio.Button>
|
|
||||||
<Radio.Button value={ColorBy.GROUP}>{ColorBy.GROUP}</Radio.Button>
|
|
||||||
<Radio.Button value={ColorBy.LABEL}>{ColorBy.LABEL}</Radio.Button>
|
|
||||||
</Radio.Group>
|
|
||||||
<Text type='secondary'>Opacity</Text>
|
|
||||||
<Slider
|
|
||||||
onChange={changeShapesOpacity}
|
|
||||||
value={opacity}
|
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
/>
|
|
||||||
<Text type='secondary'>Selected opacity</Text>
|
|
||||||
<Slider
|
|
||||||
onChange={changeSelectedShapesOpacity}
|
|
||||||
value={selectedOpacity}
|
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
/>
|
|
||||||
<Checkbox
|
|
||||||
onChange={changeShapesBlackBorders}
|
|
||||||
checked={blackBorders}
|
|
||||||
>
|
|
||||||
Black borders
|
|
||||||
</Checkbox>
|
|
||||||
<Checkbox
|
|
||||||
onChange={changeShowBitmap}
|
|
||||||
checked={showBitmap}
|
|
||||||
>
|
|
||||||
Show bitmap
|
|
||||||
</Checkbox>
|
|
||||||
<Checkbox
|
|
||||||
onChange={changeShowProjections}
|
|
||||||
checked={showProjections}
|
|
||||||
>
|
|
||||||
Show projections
|
|
||||||
</Checkbox>
|
|
||||||
</div>
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default React.memo(AppearanceBlock);
|
|
||||||
@ -0,0 +1,175 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { Col } from 'antd/lib/grid';
|
||||||
|
import Select from 'antd/lib/select';
|
||||||
|
import Radio, { RadioChangeEvent } from 'antd/lib/radio';
|
||||||
|
import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox';
|
||||||
|
import Input from 'antd/lib/input';
|
||||||
|
import InputNumber from 'antd/lib/input-number';
|
||||||
|
import Text from 'antd/lib/typography/Text';
|
||||||
|
|
||||||
|
import consts from 'consts';
|
||||||
|
import { clamp } from 'utils/math';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
attrInputType: string;
|
||||||
|
attrValues: string[];
|
||||||
|
attrValue: string;
|
||||||
|
attrName: string;
|
||||||
|
attrID: number;
|
||||||
|
changeAttribute(attrID: number, value: string): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function attrIsTheSame(
|
||||||
|
prevProps: Props,
|
||||||
|
nextProps: Props,
|
||||||
|
): boolean {
|
||||||
|
return nextProps.attrID === prevProps.attrID
|
||||||
|
&& nextProps.attrValue === prevProps.attrValue
|
||||||
|
&& nextProps.attrName === prevProps.attrName
|
||||||
|
&& nextProps.attrInputType === prevProps.attrInputType
|
||||||
|
&& nextProps.attrValues
|
||||||
|
.map((value: string, id: number): boolean => prevProps.attrValues[id] === value)
|
||||||
|
.every((value: boolean): boolean => value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ItemAttributeComponent(props: Props): JSX.Element {
|
||||||
|
const {
|
||||||
|
attrInputType,
|
||||||
|
attrValues,
|
||||||
|
attrValue,
|
||||||
|
attrName,
|
||||||
|
attrID,
|
||||||
|
changeAttribute,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
if (attrInputType === 'checkbox') {
|
||||||
|
return (
|
||||||
|
<Col span={24}>
|
||||||
|
<Checkbox
|
||||||
|
className='cvat-object-item-checkbox-attribute'
|
||||||
|
checked={attrValue === 'true'}
|
||||||
|
onChange={(event: CheckboxChangeEvent): void => {
|
||||||
|
const value = event.target.checked ? 'true' : 'false';
|
||||||
|
changeAttribute(attrID, value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text strong className='cvat-text'>
|
||||||
|
{attrName}
|
||||||
|
</Text>
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrInputType === 'radio') {
|
||||||
|
return (
|
||||||
|
<Col span={24}>
|
||||||
|
<fieldset className='cvat-object-item-radio-attribute'>
|
||||||
|
<legend>
|
||||||
|
<Text strong className='cvat-text'>{attrName}</Text>
|
||||||
|
</legend>
|
||||||
|
<Radio.Group
|
||||||
|
size='small'
|
||||||
|
value={attrValue}
|
||||||
|
onChange={(event: RadioChangeEvent): void => {
|
||||||
|
changeAttribute(attrID, event.target.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ attrValues.map((value: string): JSX.Element => (
|
||||||
|
<Radio key={value} value={value}>
|
||||||
|
{value === consts.UNDEFINED_ATTRIBUTE_VALUE
|
||||||
|
? consts.NO_BREAK_SPACE : value}
|
||||||
|
</Radio>
|
||||||
|
)) }
|
||||||
|
</Radio.Group>
|
||||||
|
</fieldset>
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrInputType === 'select') {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Col span={24}>
|
||||||
|
<Text strong className='cvat-text'>
|
||||||
|
{attrName}
|
||||||
|
</Text>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Select
|
||||||
|
size='small'
|
||||||
|
onChange={(value: string): void => {
|
||||||
|
changeAttribute(attrID, value);
|
||||||
|
}}
|
||||||
|
value={attrValue}
|
||||||
|
className='cvat-object-item-select-attribute'
|
||||||
|
>
|
||||||
|
{ attrValues.map((value: string): JSX.Element => (
|
||||||
|
<Select.Option key={value} value={value}>
|
||||||
|
{value === consts.UNDEFINED_ATTRIBUTE_VALUE
|
||||||
|
? consts.NO_BREAK_SPACE : value}
|
||||||
|
</Select.Option>
|
||||||
|
)) }
|
||||||
|
</Select>
|
||||||
|
</Col>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attrInputType === 'number') {
|
||||||
|
const [min, max, step] = attrValues.map((value: string): number => +value);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Col span={24}>
|
||||||
|
<Text strong className='cvat-text'>
|
||||||
|
{attrName}
|
||||||
|
</Text>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<InputNumber
|
||||||
|
size='small'
|
||||||
|
onChange={(value: number | undefined): void => {
|
||||||
|
if (typeof (value) === 'number') {
|
||||||
|
changeAttribute(
|
||||||
|
attrID, `${clamp(value, min, max)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
value={+attrValue}
|
||||||
|
className='cvat-object-item-number-attribute'
|
||||||
|
min={min}
|
||||||
|
max={max}
|
||||||
|
step={step}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Col span={24}>
|
||||||
|
<Text strong className='cvat-text'>
|
||||||
|
{attrName}
|
||||||
|
</Text>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Input
|
||||||
|
size='small'
|
||||||
|
onChange={(event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
changeAttribute(attrID, event.target.value);
|
||||||
|
}}
|
||||||
|
value={attrValue}
|
||||||
|
className='cvat-object-item-text-attribute'
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(ItemAttributeComponent, attrIsTheSame);
|
||||||
@ -0,0 +1,131 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { Row, Col } from 'antd/lib/grid';
|
||||||
|
import Icon from 'antd/lib/icon';
|
||||||
|
import Select, { OptionProps } from 'antd/lib/select';
|
||||||
|
import Dropdown from 'antd/lib/dropdown';
|
||||||
|
import Text from 'antd/lib/typography/Text';
|
||||||
|
import Tooltip from 'antd/lib/tooltip';
|
||||||
|
|
||||||
|
import { ObjectType, ShapeType } from 'reducers/interfaces';
|
||||||
|
import ItemMenu from './object-item-menu';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
clientID: number;
|
||||||
|
serverID: number | undefined;
|
||||||
|
labelID: number;
|
||||||
|
labels: any[];
|
||||||
|
shapeType: ShapeType;
|
||||||
|
objectType: ObjectType;
|
||||||
|
type: string;
|
||||||
|
locked: boolean;
|
||||||
|
copyShortcut: string;
|
||||||
|
pasteShortcut: string;
|
||||||
|
propagateShortcut: string;
|
||||||
|
toBackgroundShortcut: string;
|
||||||
|
toForegroundShortcut: string;
|
||||||
|
removeShortcut: string;
|
||||||
|
changeLabel(labelID: string): void;
|
||||||
|
copy(): void;
|
||||||
|
remove(): void;
|
||||||
|
propagate(): void;
|
||||||
|
createURL(): void;
|
||||||
|
switchOrientation(): void;
|
||||||
|
toBackground(): void;
|
||||||
|
toForeground(): void;
|
||||||
|
resetCuboidPerspective(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ItemTopComponent(props: Props): JSX.Element {
|
||||||
|
const {
|
||||||
|
clientID,
|
||||||
|
serverID,
|
||||||
|
labelID,
|
||||||
|
labels,
|
||||||
|
shapeType,
|
||||||
|
objectType,
|
||||||
|
type,
|
||||||
|
locked,
|
||||||
|
copyShortcut,
|
||||||
|
pasteShortcut,
|
||||||
|
propagateShortcut,
|
||||||
|
toBackgroundShortcut,
|
||||||
|
toForegroundShortcut,
|
||||||
|
removeShortcut,
|
||||||
|
changeLabel,
|
||||||
|
copy,
|
||||||
|
remove,
|
||||||
|
propagate,
|
||||||
|
createURL,
|
||||||
|
switchOrientation,
|
||||||
|
toBackground,
|
||||||
|
toForeground,
|
||||||
|
resetCuboidPerspective,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Row type='flex' align='middle'>
|
||||||
|
<Col span={10}>
|
||||||
|
<Text style={{ fontSize: 12 }}>{clientID}</Text>
|
||||||
|
<br />
|
||||||
|
<Text type='secondary' style={{ fontSize: 10 }}>{type}</Text>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Tooltip title='Change current label'>
|
||||||
|
<Select
|
||||||
|
size='small'
|
||||||
|
value={`${labelID}`}
|
||||||
|
onChange={changeLabel}
|
||||||
|
showSearch
|
||||||
|
filterOption={(input: string, option: React.ReactElement<OptionProps>) => {
|
||||||
|
const { children } = option.props;
|
||||||
|
if (typeof (children) === 'string') {
|
||||||
|
return children.toLowerCase().includes(input.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ labels.map((label: any): JSX.Element => (
|
||||||
|
<Select.Option key={label.id} value={`${label.id}`}>
|
||||||
|
{label.name}
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
<Col span={2}>
|
||||||
|
<Dropdown
|
||||||
|
placement='bottomLeft'
|
||||||
|
overlay={ItemMenu({
|
||||||
|
serverID,
|
||||||
|
locked,
|
||||||
|
shapeType,
|
||||||
|
objectType,
|
||||||
|
copyShortcut,
|
||||||
|
pasteShortcut,
|
||||||
|
propagateShortcut,
|
||||||
|
toBackgroundShortcut,
|
||||||
|
toForegroundShortcut,
|
||||||
|
removeShortcut,
|
||||||
|
copy,
|
||||||
|
remove,
|
||||||
|
propagate,
|
||||||
|
createURL,
|
||||||
|
switchOrientation,
|
||||||
|
toBackground,
|
||||||
|
toForeground,
|
||||||
|
resetCuboidPerspective,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Icon type='more' />
|
||||||
|
</Dropdown>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(ItemTopComponent);
|
||||||
@ -0,0 +1,262 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { Row, Col } from 'antd/lib/grid';
|
||||||
|
import Icon from 'antd/lib/icon';
|
||||||
|
import Tooltip from 'antd/lib/tooltip';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ObjectOutsideIcon,
|
||||||
|
FirstIcon,
|
||||||
|
LastIcon,
|
||||||
|
PreviousIcon,
|
||||||
|
NextIcon,
|
||||||
|
} from 'icons';
|
||||||
|
import { ObjectType, ShapeType } from 'reducers/interfaces';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
objectType: ObjectType;
|
||||||
|
shapeType: ShapeType;
|
||||||
|
occluded: boolean;
|
||||||
|
outside: boolean | undefined;
|
||||||
|
locked: boolean;
|
||||||
|
pinned: boolean;
|
||||||
|
hidden: boolean;
|
||||||
|
keyframe: boolean | undefined;
|
||||||
|
outsideDisabled: boolean;
|
||||||
|
hiddenDisabled: boolean;
|
||||||
|
keyframeDisabled: boolean;
|
||||||
|
switchOccludedShortcut: string;
|
||||||
|
switchOutsideShortcut: string;
|
||||||
|
switchLockShortcut: string;
|
||||||
|
switchHiddenShortcut: string;
|
||||||
|
switchKeyFrameShortcut: string;
|
||||||
|
nextKeyFrameShortcut: string;
|
||||||
|
prevKeyFrameShortcut: string;
|
||||||
|
|
||||||
|
navigateFirstKeyframe: null | (() => void);
|
||||||
|
navigatePrevKeyframe: null | (() => void);
|
||||||
|
navigateNextKeyframe: null | (() => void);
|
||||||
|
navigateLastKeyframe: null | (() => void);
|
||||||
|
|
||||||
|
setOccluded(): void;
|
||||||
|
unsetOccluded(): void;
|
||||||
|
setOutside(): void;
|
||||||
|
unsetOutside(): void;
|
||||||
|
setKeyframe(): void;
|
||||||
|
unsetKeyframe(): void;
|
||||||
|
lock(): void;
|
||||||
|
unlock(): void;
|
||||||
|
pin(): void;
|
||||||
|
unpin(): void;
|
||||||
|
hide(): void;
|
||||||
|
show(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ItemButtonsComponent(props: Props): JSX.Element {
|
||||||
|
const {
|
||||||
|
objectType,
|
||||||
|
shapeType,
|
||||||
|
occluded,
|
||||||
|
outside,
|
||||||
|
locked,
|
||||||
|
pinned,
|
||||||
|
hidden,
|
||||||
|
keyframe,
|
||||||
|
outsideDisabled,
|
||||||
|
hiddenDisabled,
|
||||||
|
keyframeDisabled,
|
||||||
|
switchOccludedShortcut,
|
||||||
|
switchOutsideShortcut,
|
||||||
|
switchLockShortcut,
|
||||||
|
switchHiddenShortcut,
|
||||||
|
switchKeyFrameShortcut,
|
||||||
|
nextKeyFrameShortcut,
|
||||||
|
prevKeyFrameShortcut,
|
||||||
|
|
||||||
|
navigateFirstKeyframe,
|
||||||
|
navigatePrevKeyframe,
|
||||||
|
navigateNextKeyframe,
|
||||||
|
navigateLastKeyframe,
|
||||||
|
|
||||||
|
setOccluded,
|
||||||
|
unsetOccluded,
|
||||||
|
setOutside,
|
||||||
|
unsetOutside,
|
||||||
|
setKeyframe,
|
||||||
|
unsetKeyframe,
|
||||||
|
lock,
|
||||||
|
unlock,
|
||||||
|
pin,
|
||||||
|
unpin,
|
||||||
|
hide,
|
||||||
|
show,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const outsideStyle = outsideDisabled ? { opacity: 0.5, pointerEvents: 'none' as 'none' } : {};
|
||||||
|
const hiddenStyle = hiddenDisabled ? { opacity: 0.5, pointerEvents: 'none' as 'none' } : {};
|
||||||
|
const keyframeStyle = keyframeDisabled ? { opacity: 0.5, pointerEvents: 'none' as 'none' } : {};
|
||||||
|
|
||||||
|
|
||||||
|
if (objectType === ObjectType.TRACK) {
|
||||||
|
return (
|
||||||
|
<Row type='flex' align='middle' justify='space-around'>
|
||||||
|
<Col span={20} style={{ textAlign: 'center' }}>
|
||||||
|
<Row type='flex' justify='space-around'>
|
||||||
|
<Col>
|
||||||
|
{ navigateFirstKeyframe
|
||||||
|
? <Icon component={FirstIcon} onClick={navigateFirstKeyframe} />
|
||||||
|
: <Icon component={FirstIcon} style={{ opacity: 0.5, pointerEvents: 'none' }} />}
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
{ navigatePrevKeyframe
|
||||||
|
? (
|
||||||
|
<Tooltip title={`Go to previous keyframe ${prevKeyFrameShortcut}`}>
|
||||||
|
<Icon
|
||||||
|
component={PreviousIcon}
|
||||||
|
onClick={navigatePrevKeyframe}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
: <Icon component={PreviousIcon} style={{ opacity: 0.5, pointerEvents: 'none' }} />}
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
{ navigateNextKeyframe
|
||||||
|
? (
|
||||||
|
<Tooltip title={`Go to next keyframe ${nextKeyFrameShortcut}`}>
|
||||||
|
<Icon
|
||||||
|
component={NextIcon}
|
||||||
|
onClick={navigateNextKeyframe}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
: <Icon component={NextIcon} style={{ opacity: 0.5, pointerEvents: 'none' }} />}
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
{ navigateLastKeyframe
|
||||||
|
? <Icon component={LastIcon} onClick={navigateLastKeyframe} />
|
||||||
|
: <Icon component={LastIcon} style={{ opacity: 0.5, pointerEvents: 'none' }} />}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row type='flex' justify='space-around'>
|
||||||
|
<Col>
|
||||||
|
<Tooltip title={`Switch outside property ${switchOutsideShortcut}`}>
|
||||||
|
{ outside
|
||||||
|
? (
|
||||||
|
<Icon
|
||||||
|
component={ObjectOutsideIcon}
|
||||||
|
onClick={unsetOutside}
|
||||||
|
style={outsideStyle}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: <Icon type='select' onClick={setOutside} style={outsideStyle} />}
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<Tooltip title={`Switch lock property ${switchLockShortcut}`}>
|
||||||
|
{ locked
|
||||||
|
? <Icon type='lock' theme='filled' onClick={unlock} />
|
||||||
|
: <Icon type='unlock' onClick={lock} />}
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<Tooltip title={`Switch occluded property ${switchOccludedShortcut}`}>
|
||||||
|
{ occluded
|
||||||
|
? <Icon type='team' onClick={unsetOccluded} />
|
||||||
|
: <Icon type='user' onClick={setOccluded} />}
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<Tooltip title={`Switch hidden property ${switchHiddenShortcut}`}>
|
||||||
|
{ hidden
|
||||||
|
? <Icon type='eye-invisible' theme='filled' onClick={show} style={hiddenStyle} />
|
||||||
|
: <Icon type='eye' onClick={hide} style={hiddenStyle} />}
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<Tooltip title={`Switch keyframe property ${switchKeyFrameShortcut}`}>
|
||||||
|
{ keyframe
|
||||||
|
? <Icon type='star' theme='filled' onClick={unsetKeyframe} style={keyframeStyle} />
|
||||||
|
: <Icon type='star' onClick={setKeyframe} style={keyframeStyle} />}
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
{
|
||||||
|
shapeType !== ShapeType.POINTS && (
|
||||||
|
<Col>
|
||||||
|
<Tooltip title='Switch pinned property'>
|
||||||
|
{ pinned
|
||||||
|
? <Icon type='pushpin' theme='filled' onClick={unpin} />
|
||||||
|
: <Icon type='pushpin' onClick={pin} />}
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (objectType === ObjectType.TAG) {
|
||||||
|
return (
|
||||||
|
<Row type='flex' align='middle' justify='space-around'>
|
||||||
|
<Col span={20} style={{ textAlign: 'center' }}>
|
||||||
|
<Row type='flex' justify='space-around'>
|
||||||
|
<Col>
|
||||||
|
<Tooltip title={`Switch lock property ${switchLockShortcut}`}>
|
||||||
|
{ locked
|
||||||
|
? <Icon type='lock' onClick={unlock} theme='filled' />
|
||||||
|
: <Icon type='unlock' onClick={lock} />}
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Row type='flex' align='middle' justify='space-around'>
|
||||||
|
<Col span={20} style={{ textAlign: 'center' }}>
|
||||||
|
<Row type='flex' justify='space-around'>
|
||||||
|
<Col>
|
||||||
|
<Tooltip title={`Switch lock property ${switchLockShortcut}`}>
|
||||||
|
{ locked
|
||||||
|
? <Icon type='lock' onClick={unlock} theme='filled' />
|
||||||
|
: <Icon type='unlock' onClick={lock} />}
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<Tooltip title={`Switch occluded property ${switchOccludedShortcut}`}>
|
||||||
|
{ occluded
|
||||||
|
? <Icon type='team' onClick={unsetOccluded} />
|
||||||
|
: <Icon type='user' onClick={setOccluded} />}
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<Tooltip title={`Switch hidden property ${switchHiddenShortcut}`}>
|
||||||
|
{ hidden
|
||||||
|
? <Icon type='eye-invisible' onClick={show} />
|
||||||
|
: <Icon type='eye' onClick={hide} />}
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
{
|
||||||
|
shapeType !== ShapeType.POINTS && (
|
||||||
|
<Col>
|
||||||
|
<Tooltip title='Switch pinned property'>
|
||||||
|
{ pinned
|
||||||
|
? <Icon type='pushpin' theme='filled' onClick={unpin} />
|
||||||
|
: <Icon type='pushpin' onClick={pin} />}
|
||||||
|
</Tooltip>
|
||||||
|
</Col>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(ItemButtonsComponent);
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { Row } from 'antd/lib/grid';
|
||||||
|
import Collapse from 'antd/lib/collapse';
|
||||||
|
|
||||||
|
import ItemAttribute from './object-item-attribute';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
collapsed: boolean;
|
||||||
|
attributes: any[];
|
||||||
|
values: Record<number, string>;
|
||||||
|
changeAttribute(attrID: number, value: string): void;
|
||||||
|
collapse(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function attrValuesAreEqual(
|
||||||
|
next: Record<number, string>, prev: Record<number, string>,
|
||||||
|
): boolean {
|
||||||
|
const prevKeys = Object.keys(prev);
|
||||||
|
const nextKeys = Object.keys(next);
|
||||||
|
|
||||||
|
return nextKeys.length === prevKeys.length
|
||||||
|
&& nextKeys.map((key: string): boolean => prev[+key] === next[+key])
|
||||||
|
.every((value: boolean) => value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function attrAreTheSame(
|
||||||
|
prevProps: Props,
|
||||||
|
nextProps: Props,
|
||||||
|
): boolean {
|
||||||
|
return nextProps.collapsed === prevProps.collapsed
|
||||||
|
&& nextProps.attributes === prevProps.attributes
|
||||||
|
&& attrValuesAreEqual(nextProps.values, prevProps.values);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ItemAttributesComponent(props: Props): JSX.Element {
|
||||||
|
const {
|
||||||
|
collapsed,
|
||||||
|
attributes,
|
||||||
|
values,
|
||||||
|
changeAttribute,
|
||||||
|
collapse,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const sorted = [...attributes]
|
||||||
|
.sort((a: any, b: any): number => a.inputType.localeCompare(b.inputType));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Row>
|
||||||
|
<Collapse
|
||||||
|
className='cvat-objects-sidebar-state-item-collapse'
|
||||||
|
activeKey={collapsed ? [] : ['details']}
|
||||||
|
onChange={collapse}
|
||||||
|
>
|
||||||
|
<Collapse.Panel
|
||||||
|
header={<span style={{ fontSize: '11px' }}>Details</span>}
|
||||||
|
key='details'
|
||||||
|
>
|
||||||
|
{ sorted.map((attribute: any): JSX.Element => (
|
||||||
|
<Row
|
||||||
|
key={attribute.id}
|
||||||
|
type='flex'
|
||||||
|
align='middle'
|
||||||
|
justify='start'
|
||||||
|
className='cvat-object-item-attribute-wrapper'
|
||||||
|
>
|
||||||
|
<ItemAttribute
|
||||||
|
attrValue={values[attribute.id]}
|
||||||
|
attrInputType={attribute.inputType}
|
||||||
|
attrName={attribute.name}
|
||||||
|
attrID={attribute.id}
|
||||||
|
attrValues={attribute.values}
|
||||||
|
changeAttribute={changeAttribute}
|
||||||
|
/>
|
||||||
|
</Row>
|
||||||
|
))}
|
||||||
|
</Collapse.Panel>
|
||||||
|
</Collapse>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(ItemAttributesComponent, attrAreTheSame);
|
||||||
@ -0,0 +1,139 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import Icon from 'antd/lib/icon';
|
||||||
|
import Menu from 'antd/lib/menu';
|
||||||
|
import Button from 'antd/lib/button';
|
||||||
|
import Modal from 'antd/lib/modal';
|
||||||
|
import Tooltip from 'antd/lib/tooltip';
|
||||||
|
|
||||||
|
import { BackgroundIcon, ForegroundIcon, ResetPerspectiveIcon } from 'icons';
|
||||||
|
import { ObjectType, ShapeType } from 'reducers/interfaces';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
serverID: number | undefined;
|
||||||
|
locked: boolean;
|
||||||
|
shapeType: ShapeType;
|
||||||
|
objectType: ObjectType;
|
||||||
|
copyShortcut: string;
|
||||||
|
pasteShortcut: string;
|
||||||
|
propagateShortcut: string;
|
||||||
|
toBackgroundShortcut: string;
|
||||||
|
toForegroundShortcut: string;
|
||||||
|
removeShortcut: string;
|
||||||
|
copy: (() => void);
|
||||||
|
remove: (() => void);
|
||||||
|
propagate: (() => void);
|
||||||
|
createURL: (() => void);
|
||||||
|
switchOrientation: (() => void);
|
||||||
|
toBackground: (() => void);
|
||||||
|
toForeground: (() => void);
|
||||||
|
resetCuboidPerspective: (() => void);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ItemMenu(props: Props): JSX.Element {
|
||||||
|
const {
|
||||||
|
serverID,
|
||||||
|
locked,
|
||||||
|
shapeType,
|
||||||
|
objectType,
|
||||||
|
copyShortcut,
|
||||||
|
pasteShortcut,
|
||||||
|
propagateShortcut,
|
||||||
|
toBackgroundShortcut,
|
||||||
|
toForegroundShortcut,
|
||||||
|
removeShortcut,
|
||||||
|
copy,
|
||||||
|
remove,
|
||||||
|
propagate,
|
||||||
|
createURL,
|
||||||
|
switchOrientation,
|
||||||
|
toBackground,
|
||||||
|
toForeground,
|
||||||
|
resetCuboidPerspective,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Menu className='cvat-object-item-menu'>
|
||||||
|
<Menu.Item>
|
||||||
|
<Button disabled={serverID === undefined} type='link' icon='link' onClick={createURL}>
|
||||||
|
Create object URL
|
||||||
|
</Button>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item>
|
||||||
|
<Tooltip title={`${copyShortcut} and ${pasteShortcut}`}>
|
||||||
|
<Button type='link' icon='copy' onClick={copy}>
|
||||||
|
Make a copy
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item>
|
||||||
|
<Tooltip title={`${propagateShortcut}`}>
|
||||||
|
<Button type='link' icon='block' onClick={propagate}>
|
||||||
|
Propagate
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Menu.Item>
|
||||||
|
{ [ShapeType.POLYGON, ShapeType.POLYLINE, ShapeType.CUBOID].includes(shapeType) && (
|
||||||
|
<Menu.Item>
|
||||||
|
<Button type='link' icon='retweet' onClick={switchOrientation}>
|
||||||
|
Switch orientation
|
||||||
|
</Button>
|
||||||
|
</Menu.Item>
|
||||||
|
)}
|
||||||
|
{shapeType === ShapeType.CUBOID && (
|
||||||
|
<Menu.Item>
|
||||||
|
<Button type='link' onClick={resetCuboidPerspective}>
|
||||||
|
<Icon component={ResetPerspectiveIcon} />
|
||||||
|
Reset perspective
|
||||||
|
</Button>
|
||||||
|
</Menu.Item>
|
||||||
|
)}
|
||||||
|
{objectType !== ObjectType.TAG && (
|
||||||
|
<Menu.Item>
|
||||||
|
<Tooltip title={`${toBackgroundShortcut}`}>
|
||||||
|
<Button type='link' onClick={toBackground}>
|
||||||
|
<Icon component={BackgroundIcon} />
|
||||||
|
To background
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Menu.Item>
|
||||||
|
)}
|
||||||
|
{objectType !== ObjectType.TAG && (
|
||||||
|
<Menu.Item>
|
||||||
|
<Tooltip title={`${toForegroundShortcut}`}>
|
||||||
|
<Button type='link' onClick={toForeground}>
|
||||||
|
<Icon component={ForegroundIcon} />
|
||||||
|
To foreground
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Menu.Item>
|
||||||
|
)}
|
||||||
|
<Menu.Item>
|
||||||
|
<Tooltip title={`${removeShortcut}`}>
|
||||||
|
<Button
|
||||||
|
type='link'
|
||||||
|
icon='delete'
|
||||||
|
onClick={(): void => {
|
||||||
|
if (locked) {
|
||||||
|
Modal.confirm({
|
||||||
|
title: 'Object is locked',
|
||||||
|
content: 'Are you sure you want to remove it?',
|
||||||
|
onOk() {
|
||||||
|
remove();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
remove();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,296 @@
|
|||||||
|
// Copyright (C) 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
import { LogType } from 'cvat-logger';
|
||||||
|
import { Canvas } from 'cvat-canvas-wrapper';
|
||||||
|
import { ThunkDispatch } from 'utils/redux';
|
||||||
|
import { updateAnnotationsAsync, changeFrameAsync } from 'actions/annotation-actions';
|
||||||
|
import { CombinedState } from 'reducers/interfaces';
|
||||||
|
import ItemButtonsComponent from 'components/annotation-page/standard-workspace/objects-side-bar/object-item-buttons';
|
||||||
|
|
||||||
|
interface OwnProps {
|
||||||
|
clientID: number;
|
||||||
|
outsideDisabled?: boolean;
|
||||||
|
hiddenDisabled?: boolean;
|
||||||
|
keyframeDisabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StateToProps {
|
||||||
|
objectState: any;
|
||||||
|
jobInstance: any;
|
||||||
|
frameNumber: number;
|
||||||
|
normalizedKeyMap: Record<string, string>;
|
||||||
|
canvasInstance: Canvas;
|
||||||
|
outsideDisabled: boolean;
|
||||||
|
hiddenDisabled: boolean;
|
||||||
|
keyframeDisabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DispatchToProps {
|
||||||
|
updateAnnotations(statesToUpdate: any[]): void;
|
||||||
|
changeFrame(frame: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps {
|
||||||
|
const {
|
||||||
|
annotation: {
|
||||||
|
annotations: {
|
||||||
|
states,
|
||||||
|
},
|
||||||
|
job: {
|
||||||
|
instance: jobInstance,
|
||||||
|
},
|
||||||
|
player: {
|
||||||
|
frame: {
|
||||||
|
number: frameNumber,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
canvas: {
|
||||||
|
instance: canvasInstance,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shortcuts: {
|
||||||
|
normalizedKeyMap,
|
||||||
|
},
|
||||||
|
} = state;
|
||||||
|
|
||||||
|
const {
|
||||||
|
clientID,
|
||||||
|
outsideDisabled,
|
||||||
|
hiddenDisabled,
|
||||||
|
keyframeDisabled,
|
||||||
|
} = own;
|
||||||
|
const [objectState] = states
|
||||||
|
.filter((_objectState): boolean => _objectState.clientID === clientID);
|
||||||
|
|
||||||
|
return {
|
||||||
|
objectState,
|
||||||
|
normalizedKeyMap,
|
||||||
|
frameNumber,
|
||||||
|
jobInstance,
|
||||||
|
canvasInstance,
|
||||||
|
outsideDisabled: typeof (outsideDisabled) === 'undefined' ? false : outsideDisabled,
|
||||||
|
hiddenDisabled: typeof (hiddenDisabled) === 'undefined' ? false : hiddenDisabled,
|
||||||
|
keyframeDisabled: typeof (keyframeDisabled) === 'undefined' ? false : keyframeDisabled,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps(dispatch: ThunkDispatch): DispatchToProps {
|
||||||
|
return {
|
||||||
|
updateAnnotations(states: any[]) {
|
||||||
|
dispatch(updateAnnotationsAsync(states));
|
||||||
|
},
|
||||||
|
changeFrame(frame: number): void {
|
||||||
|
dispatch(changeFrameAsync(frame));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class ItemButtonsWrapper extends React.PureComponent<StateToProps & DispatchToProps> {
|
||||||
|
private navigateFirstKeyframe = (): void => {
|
||||||
|
const { objectState, frameNumber } = this.props;
|
||||||
|
const { first } = objectState.keyframes;
|
||||||
|
if (first !== frameNumber) {
|
||||||
|
this.changeFrame(first);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private navigatePrevKeyframe = (): void => {
|
||||||
|
const { objectState, frameNumber } = this.props;
|
||||||
|
const { prev } = objectState.keyframes;
|
||||||
|
if (prev !== null && prev !== frameNumber) {
|
||||||
|
this.changeFrame(prev);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private navigateNextKeyframe = (): void => {
|
||||||
|
const { objectState, frameNumber } = this.props;
|
||||||
|
const { next } = objectState.keyframes;
|
||||||
|
if (next !== null && next !== frameNumber) {
|
||||||
|
this.changeFrame(next);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private navigateLastKeyframe = (): void => {
|
||||||
|
const { objectState, frameNumber } = this.props;
|
||||||
|
const { last } = objectState.keyframes;
|
||||||
|
if (last !== frameNumber) {
|
||||||
|
this.changeFrame(last);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private lock = (): void => {
|
||||||
|
const { objectState, jobInstance } = this.props;
|
||||||
|
jobInstance.logger.log(LogType.lockObject, { locked: true });
|
||||||
|
objectState.lock = true;
|
||||||
|
this.commit();
|
||||||
|
};
|
||||||
|
|
||||||
|
private unlock = (): void => {
|
||||||
|
const { objectState, jobInstance } = this.props;
|
||||||
|
jobInstance.logger.log(LogType.lockObject, { locked: false });
|
||||||
|
objectState.lock = false;
|
||||||
|
this.commit();
|
||||||
|
};
|
||||||
|
|
||||||
|
private pin = (): void => {
|
||||||
|
const { objectState } = this.props;
|
||||||
|
objectState.pinned = true;
|
||||||
|
this.commit();
|
||||||
|
};
|
||||||
|
|
||||||
|
private unpin = (): void => {
|
||||||
|
const { objectState } = this.props;
|
||||||
|
objectState.pinned = false;
|
||||||
|
this.commit();
|
||||||
|
};
|
||||||
|
|
||||||
|
private show = (): void => {
|
||||||
|
const { objectState } = this.props;
|
||||||
|
objectState.hidden = false;
|
||||||
|
this.commit();
|
||||||
|
};
|
||||||
|
|
||||||
|
private hide = (): void => {
|
||||||
|
const { objectState } = this.props;
|
||||||
|
objectState.hidden = true;
|
||||||
|
this.commit();
|
||||||
|
};
|
||||||
|
|
||||||
|
private setOccluded = (): void => {
|
||||||
|
const { objectState } = this.props;
|
||||||
|
objectState.occluded = true;
|
||||||
|
this.commit();
|
||||||
|
};
|
||||||
|
|
||||||
|
private unsetOccluded = (): void => {
|
||||||
|
const { objectState } = this.props;
|
||||||
|
objectState.occluded = false;
|
||||||
|
this.commit();
|
||||||
|
};
|
||||||
|
|
||||||
|
private setOutside = (): void => {
|
||||||
|
const { objectState } = this.props;
|
||||||
|
objectState.outside = true;
|
||||||
|
this.commit();
|
||||||
|
};
|
||||||
|
|
||||||
|
private unsetOutside = (): void => {
|
||||||
|
const { objectState } = this.props;
|
||||||
|
objectState.outside = false;
|
||||||
|
this.commit();
|
||||||
|
};
|
||||||
|
|
||||||
|
private setKeyframe = (): void => {
|
||||||
|
const { objectState } = this.props;
|
||||||
|
objectState.keyframe = true;
|
||||||
|
this.commit();
|
||||||
|
};
|
||||||
|
|
||||||
|
private unsetKeyframe = (): void => {
|
||||||
|
const { objectState } = this.props;
|
||||||
|
objectState.keyframe = false;
|
||||||
|
this.commit();
|
||||||
|
};
|
||||||
|
|
||||||
|
private commit(): void {
|
||||||
|
const {
|
||||||
|
objectState,
|
||||||
|
updateAnnotations,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
updateAnnotations([objectState]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private changeFrame(frame: number): void {
|
||||||
|
const { changeFrame, canvasInstance } = this.props;
|
||||||
|
if (canvasInstance.isAbleToChangeFrame()) {
|
||||||
|
changeFrame(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): JSX.Element {
|
||||||
|
const {
|
||||||
|
objectState,
|
||||||
|
normalizedKeyMap,
|
||||||
|
frameNumber,
|
||||||
|
outsideDisabled,
|
||||||
|
hiddenDisabled,
|
||||||
|
keyframeDisabled,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const {
|
||||||
|
first,
|
||||||
|
prev,
|
||||||
|
next,
|
||||||
|
last,
|
||||||
|
} = objectState.keyframes || {
|
||||||
|
first: null, // shapes don't have keyframes, so we use null
|
||||||
|
prev: null,
|
||||||
|
next: null,
|
||||||
|
last: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ItemButtonsComponent
|
||||||
|
objectType={objectState.objectType}
|
||||||
|
shapeType={objectState.shapeType}
|
||||||
|
occluded={objectState.occluded}
|
||||||
|
outside={objectState.outside}
|
||||||
|
locked={objectState.lock}
|
||||||
|
pinned={objectState.pinned}
|
||||||
|
hidden={objectState.hidden}
|
||||||
|
keyframe={objectState.keyframe}
|
||||||
|
switchOccludedShortcut={normalizedKeyMap.SWITCH_OCCLUDED}
|
||||||
|
switchOutsideShortcut={normalizedKeyMap.SWITCH_OUTSIDE}
|
||||||
|
switchLockShortcut={normalizedKeyMap.SWITCH_LOCK}
|
||||||
|
switchHiddenShortcut={normalizedKeyMap.SWITCH_HIDDEN}
|
||||||
|
switchKeyFrameShortcut={normalizedKeyMap.SWITCH_KEYFRAME}
|
||||||
|
nextKeyFrameShortcut={normalizedKeyMap.NEXT_KEY_FRAME}
|
||||||
|
prevKeyFrameShortcut={normalizedKeyMap.PREV_KEY_FRAME}
|
||||||
|
outsideDisabled={outsideDisabled}
|
||||||
|
hiddenDisabled={hiddenDisabled}
|
||||||
|
keyframeDisabled={keyframeDisabled}
|
||||||
|
|
||||||
|
navigateFirstKeyframe={
|
||||||
|
first >= frameNumber || first === null
|
||||||
|
? null : this.navigateFirstKeyframe
|
||||||
|
}
|
||||||
|
navigatePrevKeyframe={
|
||||||
|
prev === frameNumber || prev === null
|
||||||
|
? null : this.navigatePrevKeyframe
|
||||||
|
}
|
||||||
|
navigateNextKeyframe={
|
||||||
|
next === frameNumber || next === null
|
||||||
|
? null : this.navigateNextKeyframe
|
||||||
|
}
|
||||||
|
navigateLastKeyframe={
|
||||||
|
last <= frameNumber || last === null
|
||||||
|
? null : this.navigateLastKeyframe
|
||||||
|
}
|
||||||
|
|
||||||
|
setOccluded={this.setOccluded}
|
||||||
|
unsetOccluded={this.unsetOccluded}
|
||||||
|
setOutside={this.setOutside}
|
||||||
|
unsetOutside={this.unsetOutside}
|
||||||
|
setKeyframe={this.setKeyframe}
|
||||||
|
unsetKeyframe={this.unsetKeyframe}
|
||||||
|
lock={this.lock}
|
||||||
|
unlock={this.unlock}
|
||||||
|
pin={this.pin}
|
||||||
|
unpin={this.unpin}
|
||||||
|
hide={this.hide}
|
||||||
|
show={this.show}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps,
|
||||||
|
)(ItemButtonsWrapper);
|
||||||
@ -1,254 +0,0 @@
|
|||||||
// Copyright (C) 2020 Intel Corporation
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
|
|
||||||
import { RadioChangeEvent } from 'antd/lib/radio';
|
|
||||||
import { SliderValue } from 'antd/lib/slider';
|
|
||||||
import { CheckboxChangeEvent } from 'antd/lib/checkbox';
|
|
||||||
|
|
||||||
import ObjectsSidebarComponent from 'components/annotation-page/standard-workspace/objects-side-bar/objects-side-bar';
|
|
||||||
import {
|
|
||||||
CombinedState,
|
|
||||||
ColorBy,
|
|
||||||
} from 'reducers/interfaces';
|
|
||||||
|
|
||||||
import {
|
|
||||||
collapseSidebar as collapseSidebarAction,
|
|
||||||
collapseAppearance as collapseAppearanceAction,
|
|
||||||
updateTabContentHeight as updateTabContentHeightAction,
|
|
||||||
} from 'actions/annotation-actions';
|
|
||||||
|
|
||||||
import {
|
|
||||||
changeShapesColorBy as changeShapesColorByAction,
|
|
||||||
changeShapesOpacity as changeShapesOpacityAction,
|
|
||||||
changeSelectedShapesOpacity as changeSelectedShapesOpacityAction,
|
|
||||||
changeShapesBlackBorders as changeShapesBlackBordersAction,
|
|
||||||
changeShowBitmap as changeShowUnlabeledRegionsAction,
|
|
||||||
changeShowProjections as changeShowProjectionsAction,
|
|
||||||
} from 'actions/settings-actions';
|
|
||||||
|
|
||||||
import { Canvas } from 'cvat-canvas-wrapper';
|
|
||||||
|
|
||||||
interface StateToProps {
|
|
||||||
sidebarCollapsed: boolean;
|
|
||||||
appearanceCollapsed: boolean;
|
|
||||||
colorBy: ColorBy;
|
|
||||||
opacity: number;
|
|
||||||
selectedOpacity: number;
|
|
||||||
blackBorders: boolean;
|
|
||||||
showBitmap: boolean;
|
|
||||||
showProjections: boolean;
|
|
||||||
canvasInstance: Canvas;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DispatchToProps {
|
|
||||||
collapseSidebar(): void;
|
|
||||||
collapseAppearance(): void;
|
|
||||||
updateTabContentHeight(): void;
|
|
||||||
changeShapesColorBy(colorBy: ColorBy): void;
|
|
||||||
changeShapesOpacity(shapesOpacity: number): void;
|
|
||||||
changeSelectedShapesOpacity(selectedShapesOpacity: number): void;
|
|
||||||
changeShapesBlackBorders(blackBorders: boolean): void;
|
|
||||||
changeShowBitmap(showBitmap: boolean): void;
|
|
||||||
changeShowProjections(showProjections: boolean): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapStateToProps(state: CombinedState): StateToProps {
|
|
||||||
const {
|
|
||||||
annotation: {
|
|
||||||
sidebarCollapsed,
|
|
||||||
appearanceCollapsed,
|
|
||||||
canvas: {
|
|
||||||
instance: canvasInstance,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
settings: {
|
|
||||||
shapes: {
|
|
||||||
colorBy,
|
|
||||||
opacity,
|
|
||||||
selectedOpacity,
|
|
||||||
blackBorders,
|
|
||||||
showBitmap,
|
|
||||||
showProjections,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} = state;
|
|
||||||
|
|
||||||
return {
|
|
||||||
sidebarCollapsed,
|
|
||||||
appearanceCollapsed,
|
|
||||||
colorBy,
|
|
||||||
opacity,
|
|
||||||
selectedOpacity,
|
|
||||||
blackBorders,
|
|
||||||
showBitmap,
|
|
||||||
showProjections,
|
|
||||||
canvasInstance,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function computeHeight(): number {
|
|
||||||
const [sidebar] = window.document.getElementsByClassName('cvat-objects-sidebar');
|
|
||||||
const [appearance] = window.document.getElementsByClassName('cvat-objects-appearance-collapse');
|
|
||||||
const [tabs] = Array.from(
|
|
||||||
window.document.querySelectorAll('.cvat-objects-sidebar-tabs > .ant-tabs-card-bar'),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (sidebar && appearance && tabs) {
|
|
||||||
const maxHeight = sidebar ? sidebar.clientHeight : 0;
|
|
||||||
const appearanceHeight = appearance ? appearance.clientHeight : 0;
|
|
||||||
const tabsHeight = tabs ? tabs.clientHeight : 0;
|
|
||||||
return maxHeight - appearanceHeight - tabsHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch: any): DispatchToProps {
|
|
||||||
return {
|
|
||||||
collapseSidebar(): void {
|
|
||||||
dispatch(collapseSidebarAction());
|
|
||||||
},
|
|
||||||
collapseAppearance(): void {
|
|
||||||
dispatch(collapseAppearanceAction());
|
|
||||||
|
|
||||||
const [collapser] = window.document
|
|
||||||
.getElementsByClassName('cvat-objects-appearance-collapse');
|
|
||||||
|
|
||||||
if (collapser) {
|
|
||||||
collapser.addEventListener('transitionend', () => {
|
|
||||||
dispatch(
|
|
||||||
updateTabContentHeightAction(
|
|
||||||
computeHeight(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}, { once: true });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
updateTabContentHeight(): void {
|
|
||||||
dispatch(
|
|
||||||
updateTabContentHeightAction(
|
|
||||||
computeHeight(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
changeShapesColorBy(colorBy: ColorBy): void {
|
|
||||||
dispatch(changeShapesColorByAction(colorBy));
|
|
||||||
},
|
|
||||||
changeShapesOpacity(shapesOpacity: number): void {
|
|
||||||
dispatch(changeShapesOpacityAction(shapesOpacity));
|
|
||||||
},
|
|
||||||
changeSelectedShapesOpacity(selectedShapesOpacity: number): void {
|
|
||||||
dispatch(changeSelectedShapesOpacityAction(selectedShapesOpacity));
|
|
||||||
},
|
|
||||||
changeShapesBlackBorders(blackBorders: boolean): void {
|
|
||||||
dispatch(changeShapesBlackBordersAction(blackBorders));
|
|
||||||
},
|
|
||||||
changeShowBitmap(showBitmap: boolean) {
|
|
||||||
dispatch(changeShowUnlabeledRegionsAction(showBitmap));
|
|
||||||
},
|
|
||||||
changeShowProjections(showProjections: boolean) {
|
|
||||||
dispatch(changeShowProjectionsAction(showProjections));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = StateToProps & DispatchToProps;
|
|
||||||
class ObjectsSideBarContainer extends React.PureComponent<Props> {
|
|
||||||
public componentDidMount(): void {
|
|
||||||
window.addEventListener('resize', this.alignTabHeight);
|
|
||||||
this.alignTabHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillUnmount(): void {
|
|
||||||
window.removeEventListener('resize', this.alignTabHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
private alignTabHeight = (): void => {
|
|
||||||
const {
|
|
||||||
sidebarCollapsed,
|
|
||||||
updateTabContentHeight,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
if (!sidebarCollapsed) {
|
|
||||||
updateTabContentHeight();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private changeShapesColorBy = (event: RadioChangeEvent): void => {
|
|
||||||
const { changeShapesColorBy } = this.props;
|
|
||||||
changeShapesColorBy(event.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
private changeShapesOpacity = (value: SliderValue): void => {
|
|
||||||
const { changeShapesOpacity } = this.props;
|
|
||||||
changeShapesOpacity(value as number);
|
|
||||||
};
|
|
||||||
|
|
||||||
private changeSelectedShapesOpacity = (value: SliderValue): void => {
|
|
||||||
const { changeSelectedShapesOpacity } = this.props;
|
|
||||||
changeSelectedShapesOpacity(value as number);
|
|
||||||
};
|
|
||||||
|
|
||||||
private changeShapesBlackBorders = (event: CheckboxChangeEvent): void => {
|
|
||||||
const { changeShapesBlackBorders } = this.props;
|
|
||||||
changeShapesBlackBorders(event.target.checked);
|
|
||||||
};
|
|
||||||
|
|
||||||
private changeShowBitmap = (event: CheckboxChangeEvent): void => {
|
|
||||||
const { changeShowBitmap } = this.props;
|
|
||||||
changeShowBitmap(event.target.checked);
|
|
||||||
};
|
|
||||||
|
|
||||||
private changeShowProjections = (event: CheckboxChangeEvent): void => {
|
|
||||||
const { changeShowProjections } = this.props;
|
|
||||||
changeShowProjections(event.target.checked);
|
|
||||||
};
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
|
||||||
const {
|
|
||||||
sidebarCollapsed,
|
|
||||||
appearanceCollapsed,
|
|
||||||
colorBy,
|
|
||||||
opacity,
|
|
||||||
selectedOpacity,
|
|
||||||
blackBorders,
|
|
||||||
showBitmap,
|
|
||||||
showProjections,
|
|
||||||
canvasInstance,
|
|
||||||
collapseSidebar,
|
|
||||||
collapseAppearance,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ObjectsSidebarComponent
|
|
||||||
sidebarCollapsed={sidebarCollapsed}
|
|
||||||
appearanceCollapsed={appearanceCollapsed}
|
|
||||||
colorBy={colorBy}
|
|
||||||
opacity={opacity}
|
|
||||||
selectedOpacity={selectedOpacity}
|
|
||||||
blackBorders={blackBorders}
|
|
||||||
showBitmap={showBitmap}
|
|
||||||
showProjections={showProjections}
|
|
||||||
canvasInstance={canvasInstance}
|
|
||||||
collapseSidebar={collapseSidebar}
|
|
||||||
collapseAppearance={collapseAppearance}
|
|
||||||
changeShapesColorBy={this.changeShapesColorBy}
|
|
||||||
changeShapesOpacity={this.changeShapesOpacity}
|
|
||||||
changeSelectedShapesOpacity={this.changeSelectedShapesOpacity}
|
|
||||||
changeShapesBlackBorders={this.changeShapesBlackBorders}
|
|
||||||
changeShowBitmap={this.changeShowBitmap}
|
|
||||||
changeShowProjections={this.changeShowProjections}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(
|
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps,
|
|
||||||
)(ObjectsSideBarContainer);
|
|
||||||
Loading…
Reference in New Issue