Added ability to setup text labels content (#4029)

* Added ability to setup text labels content

* Updated changelog

* Fixed wrong test

* Added minimum font size const
main
Boris Sekachev 4 years ago committed by GitHub
parent 3cf5265b01
commit 6af3be6cac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Data sorting option (<https://github.com/openvinotoolkit/cvat/pull/3937>) - Data sorting option (<https://github.com/openvinotoolkit/cvat/pull/3937>)
- Options to change font size & position of text labels on the canvas (<https://github.com/openvinotoolkit/cvat/pull/3972>) - Options to change font size & position of text labels on the canvas (<https://github.com/openvinotoolkit/cvat/pull/3972>)
- Add "tag" return type for automatic annotation in Nuclio (<https://github.com/openvinotoolkit/cvat/pull/3896>) - Add "tag" return type for automatic annotation in Nuclio (<https://github.com/openvinotoolkit/cvat/pull/3896>)
- User is able to customize information that text labels show (<https://github.com/openvinotoolkit/cvat/pull/4029>)
### Changed ### Changed
- TDB - TDB

@ -1,12 +1,12 @@
{ {
"name": "cvat-canvas", "name": "cvat-canvas",
"version": "2.10.2", "version": "2.11.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "cvat-canvas", "name": "cvat-canvas",
"version": "2.10.2", "version": "2.11.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/polylabel": "^1.0.5", "@types/polylabel": "^1.0.5",

@ -1,6 +1,6 @@
{ {
"name": "cvat-canvas", "name": "cvat-canvas",
"version": "2.10.2", "version": "2.11.0",
"description": "Part of Computer Vision Annotation Tool which presents its canvas library", "description": "Part of Computer Vision Annotation Tool which presents its canvas library",
"main": "src/canvas.ts", "main": "src/canvas.ts",
"scripts": { "scripts": {

@ -2,6 +2,7 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import consts from './consts';
import { MasterImpl } from './master'; import { MasterImpl } from './master';
export interface Size { export interface Size {
@ -57,6 +58,7 @@ export interface Configuration {
displayAllText?: boolean; displayAllText?: boolean;
textFontSize?: number; textFontSize?: number;
textPosition?: 'auto' | 'center'; textPosition?: 'auto' | 'center';
textContent?: string;
undefinedAttrValue?: string; undefinedAttrValue?: string;
showProjections?: boolean; showProjections?: boolean;
forceDisableEditing?: boolean; forceDisableEditing?: boolean;
@ -263,6 +265,9 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
displayAllText: false, displayAllText: false,
autoborders: false, autoborders: false,
undefinedAttrValue: '', undefinedAttrValue: '',
textContent: 'id,label,attributes,source,descriptions',
textPosition: 'auto',
textFontSize: consts.DEFAULT_SHAPE_TEXT_SIZE,
}, },
imageBitmap: false, imageBitmap: false,
image: null, image: null,
@ -649,7 +654,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
this.data.configuration.displayAllText = configuration.displayAllText; this.data.configuration.displayAllText = configuration.displayAllText;
} }
if (typeof configuration.textFontSize === 'number') { if (typeof configuration.textFontSize === 'number' && configuration.textFontSize >= consts.MINIMUM_TEXT_FONT_SIZE) {
this.data.configuration.textFontSize = configuration.textFontSize; this.data.configuration.textFontSize = configuration.textFontSize;
} }
@ -657,6 +662,13 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
this.data.configuration.textPosition = configuration.textPosition; this.data.configuration.textPosition = configuration.textPosition;
} }
if (typeof configuration.textContent === 'string') {
const splitted = configuration.textContent.split(',').filter((entry: string) => !!entry);
if (splitted.every((entry: string) => ['id', 'label', 'attributes', 'source', 'descriptions'].includes(entry))) {
this.data.configuration.textContent = configuration.textContent;
}
}
if (typeof configuration.showProjections === 'boolean') { if (typeof configuration.showProjections === 'boolean') {
this.data.configuration.showProjections = configuration.showProjections; this.data.configuration.showProjections = configuration.showProjections;
} }

@ -1189,9 +1189,11 @@ export class CanvasViewImpl implements CanvasView, Listener {
} }
} }
const recreateText = configuration.textContent !== this.configuration.textContent;
const updateTextPosition = configuration.displayAllText !== this.configuration.displayAllText || const updateTextPosition = configuration.displayAllText !== this.configuration.displayAllText ||
configuration.textFontSize !== this.configuration.textFontSize || configuration.textFontSize !== this.configuration.textFontSize ||
configuration.textPosition !== this.configuration.textPosition; configuration.textPosition !== this.configuration.textPosition ||
recreateText;
if (configuration.smoothImage === true) { if (configuration.smoothImage === true) {
this.background.classList.remove('cvat_canvas_pixelized'); this.background.classList.remove('cvat_canvas_pixelized');
@ -1200,6 +1202,19 @@ export class CanvasViewImpl implements CanvasView, Listener {
} }
this.configuration = configuration; this.configuration = configuration;
if (recreateText) {
const states = this.controller.objects;
for (const key of Object.keys(this.drawnStates)) {
const clientID = +key;
const [state] = states.filter((_state: any) => _state.clientID === clientID);
if (clientID in this.svgTexts) {
this.svgTexts[clientID].remove();
delete this.svgTexts[clientID];
if (state) this.svgTexts[clientID] = this.addText(state);
}
}
}
if (updateTextPosition) { if (updateTextPosition) {
for (const i in this.drawnStates) { for (const i in this.drawnStates) {
if (i in this.svgTexts) { if (i in this.svgTexts) {
@ -2071,8 +2086,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
// Update text position after corresponding box has been moved, resized, etc. // Update text position after corresponding box has been moved, resized, etc.
private updateTextPosition(text: SVG.Text, shape: SVG.Shape): void { private updateTextPosition(text: SVG.Text, shape: SVG.Shape): void {
if (text.node.style.display === 'none') return; // wrong transformation matrix if (text.node.style.display === 'none') return; // wrong transformation matrix
const textFontSize = this.configuration.textFontSize || consts.DEFAULT_SHAPE_TEXT_SIZE; const { textFontSize, textPosition } = this.configuration;
const textPosition = this.configuration.textPosition || 'auto';
text.untransform(); text.untransform();
text.style({ 'font-size': `${textFontSize}px` }); text.style({ 'font-size': `${textFontSize}px` });
@ -2131,8 +2145,8 @@ export class CanvasViewImpl implements CanvasView, Listener {
// Translate found coordinates to text SVG // Translate found coordinates to text SVG
const [x, y, rotX, rotY]: number[] = translateToSVG(this.text, [ const [x, y, rotX, rotY]: number[] = translateToSVG(this.text, [
clientX + consts.TEXT_MARGIN, clientX + (textPosition === 'auto' ? consts.TEXT_MARGIN : 0),
clientY + consts.TEXT_MARGIN, clientY + (textPosition === 'auto' ? consts.TEXT_MARGIN : 0),
clientCX, clientCX,
clientCY, clientCY,
]); ]);
@ -2156,6 +2170,13 @@ export class CanvasViewImpl implements CanvasView, Listener {
private addText(state: any): SVG.Text { private addText(state: any): SVG.Text {
const { undefinedAttrValue } = this.configuration; const { undefinedAttrValue } = this.configuration;
const content = this.configuration.textContent;
const withID = content.includes('id');
const withAttr = content.includes('attributes');
const withLabel = content.includes('label');
const withSource = content.includes('source');
const withDescriptions = content.includes('descriptions');
const textFontSize = this.configuration.textFontSize || 12; const textFontSize = this.configuration.textFontSize || 12;
const { const {
label, clientID, attributes, source, descriptions, label, clientID, attributes, source, descriptions,
@ -2167,28 +2188,32 @@ export class CanvasViewImpl implements CanvasView, Listener {
return this.adoptedText return this.adoptedText
.text((block): void => { .text((block): void => {
block.tspan(`${label.name} ${clientID} (${source})`).style({ block.tspan(`${withLabel ? label.name : ''} ${withID ? clientID : ''} ${withSource ? `(${source})` : ''}`).style({
'text-transform': 'uppercase', 'text-transform': 'uppercase',
}); });
for (const desc of descriptions) { if (withDescriptions) {
block for (const desc of descriptions) {
.tspan(`${desc}`) block
.attr({ .tspan(`${desc}`)
dy: '1em', .attr({
x: 0, dy: '1em',
}) x: 0,
.addClass('cvat_canvas_text_description'); })
.addClass('cvat_canvas_text_description');
}
} }
for (const attrID of Object.keys(attributes)) { if (withAttr) {
const value = attributes[attrID] === undefinedAttrValue ? '' : attributes[attrID]; for (const attrID of Object.keys(attributes)) {
block const value = attributes[attrID] === undefinedAttrValue ? '' : attributes[attrID];
.tspan(`${attrNames[attrID]}: ${value}`) block
.attr({ .tspan(`${attrNames[attrID]}: ${value}`)
attrID, .attr({
dy: '1em', attrID,
x: 0, dy: '1em',
}) x: 0,
.addClass('cvat_canvas_text_attribute'); })
.addClass('cvat_canvas_text_attribute');
}
} }
}) })
.move(0, 0) .move(0, 0)

@ -20,6 +20,7 @@ const BASE_PATTERN_SIZE = 5;
const SNAP_TO_ANGLE_RESIZE_DEFAULT = 0.1; const SNAP_TO_ANGLE_RESIZE_DEFAULT = 0.1;
const SNAP_TO_ANGLE_RESIZE_SHIFT = 15; const SNAP_TO_ANGLE_RESIZE_SHIFT = 15;
const DEFAULT_SHAPE_TEXT_SIZE = 12; const DEFAULT_SHAPE_TEXT_SIZE = 12;
const MINIMUM_TEXT_FONT_SIZE = 8;
export default { export default {
BASE_STROKE_WIDTH, BASE_STROKE_WIDTH,
@ -39,4 +40,5 @@ export default {
SNAP_TO_ANGLE_RESIZE_DEFAULT, SNAP_TO_ANGLE_RESIZE_DEFAULT,
SNAP_TO_ANGLE_RESIZE_SHIFT, SNAP_TO_ANGLE_RESIZE_SHIFT,
DEFAULT_SHAPE_TEXT_SIZE, DEFAULT_SHAPE_TEXT_SIZE,
MINIMUM_TEXT_FONT_SIZE,
}; };

@ -1,12 +1,12 @@
{ {
"name": "cvat-ui", "name": "cvat-ui",
"version": "1.28.2", "version": "1.29.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "cvat-ui", "name": "cvat-ui",
"version": "1.28.2", "version": "1.29.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ant-design/icons": "^4.6.3", "@ant-design/icons": "^4.6.3",

@ -1,6 +1,6 @@
{ {
"name": "cvat-ui", "name": "cvat-ui",
"version": "1.28.2", "version": "1.29.0",
"description": "CVAT single-page application", "description": "CVAT single-page application",
"main": "src/index.tsx", "main": "src/index.tsx",
"scripts": { "scripts": {

@ -25,6 +25,7 @@ export enum SettingsActionTypes {
SWITCH_SMOOTH_IMAGE = 'SWITCH_SMOOTH_IMAGE', SWITCH_SMOOTH_IMAGE = 'SWITCH_SMOOTH_IMAGE',
SWITCH_TEXT_FONT_SIZE = 'SWITCH_TEXT_FONT_SIZE', SWITCH_TEXT_FONT_SIZE = 'SWITCH_TEXT_FONT_SIZE',
SWITCH_TEXT_POSITION = 'SWITCH_TEXT_POSITION', SWITCH_TEXT_POSITION = 'SWITCH_TEXT_POSITION',
SWITCH_TEXT_CONTENT = 'SWITCH_TEXT_CONTENT',
CHANGE_BRIGHTNESS_LEVEL = 'CHANGE_BRIGHTNESS_LEVEL', CHANGE_BRIGHTNESS_LEVEL = 'CHANGE_BRIGHTNESS_LEVEL',
CHANGE_CONTRAST_LEVEL = 'CHANGE_CONTRAST_LEVEL', CHANGE_CONTRAST_LEVEL = 'CHANGE_CONTRAST_LEVEL',
CHANGE_SATURATION_LEVEL = 'CHANGE_SATURATION_LEVEL', CHANGE_SATURATION_LEVEL = 'CHANGE_SATURATION_LEVEL',
@ -196,6 +197,15 @@ export function switchTextPosition(position: 'auto' | 'center'): AnyAction {
}; };
} }
export function switchTextContent(textContent: string): AnyAction {
return {
type: SettingsActionTypes.SWITCH_TEXT_CONTENT,
payload: {
textContent,
},
};
}
export function changeBrightnessLevel(level: number): AnyAction { export function changeBrightnessLevel(level: number): AnyAction {
return { return {
type: SettingsActionTypes.CHANGE_BRIGHTNESS_LEVEL, type: SettingsActionTypes.CHANGE_BRIGHTNESS_LEVEL,

@ -62,6 +62,7 @@ interface Props {
showObjectsTextAlways: boolean; showObjectsTextAlways: boolean;
textFontSize: number; textFontSize: number;
textPosition: 'auto' | 'center'; textPosition: 'auto' | 'center';
textContent: string;
showAllInterpolationTracks: boolean; showAllInterpolationTracks: boolean;
workspace: Workspace; workspace: Workspace;
automaticBordering: boolean; automaticBordering: boolean;
@ -111,6 +112,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
smoothImage, smoothImage,
textFontSize, textFontSize,
textPosition, textPosition,
textContent,
} = this.props; } = this.props;
const { canvasInstance } = this.props as { canvasInstance: Canvas }; const { canvasInstance } = this.props as { canvasInstance: Canvas };
@ -130,6 +132,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
creationOpacity: selectedOpacity, creationOpacity: selectedOpacity,
textFontSize, textFontSize,
textPosition, textPosition,
textContent,
}); });
this.initialSetup(); this.initialSetup();
@ -166,6 +169,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
showObjectsTextAlways, showObjectsTextAlways,
textFontSize, textFontSize,
textPosition, textPosition,
textContent,
showAllInterpolationTracks, showAllInterpolationTracks,
automaticBordering, automaticBordering,
intelligentPolygonCrop, intelligentPolygonCrop,
@ -182,7 +186,8 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
prevProps.selectedOpacity !== selectedOpacity || prevProps.selectedOpacity !== selectedOpacity ||
prevProps.smoothImage !== smoothImage || prevProps.smoothImage !== smoothImage ||
prevProps.textFontSize !== textFontSize || prevProps.textFontSize !== textFontSize ||
prevProps.textPosition !== textPosition prevProps.textPosition !== textPosition ||
prevProps.textContent !== textContent
) { ) {
canvasInstance.configure({ canvasInstance.configure({
undefinedAttrValue: consts.UNDEFINED_ATTRIBUTE_VALUE, undefinedAttrValue: consts.UNDEFINED_ATTRIBUTE_VALUE,
@ -194,6 +199,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
smoothImage, smoothImage,
textFontSize, textFontSize,
textPosition, textPosition,
textContent,
}); });
} }

@ -38,6 +38,10 @@
} }
} }
.cvat-workspace-settings-text-content {
width: 100%;
}
.cvat-workspace-settings-approx-poly-threshold { .cvat-workspace-settings-approx-poly-threshold {
user-select: none; user-select: none;
} }

@ -9,13 +9,13 @@ import Checkbox, { CheckboxChangeEvent } from 'antd/lib/checkbox';
import InputNumber from 'antd/lib/input-number'; import InputNumber from 'antd/lib/input-number';
import Text from 'antd/lib/typography/Text'; import Text from 'antd/lib/typography/Text';
import Slider from 'antd/lib/slider'; import Slider from 'antd/lib/slider';
import Select from 'antd/lib/select';
import { import {
MAX_ACCURACY, MAX_ACCURACY,
marks, marks,
} from 'components/annotation-page/standard-workspace/controls-side-bar/approximation-accuracy'; } from 'components/annotation-page/standard-workspace/controls-side-bar/approximation-accuracy';
import { clamp } from 'utils/math'; import { clamp } from 'utils/math';
import { Select } from 'antd';
interface Props { interface Props {
autoSave: boolean; autoSave: boolean;
@ -28,6 +28,7 @@ interface Props {
defaultApproxPolyAccuracy: number; defaultApproxPolyAccuracy: number;
textFontSize: number; textFontSize: number;
textPosition: 'center' | 'auto'; textPosition: 'center' | 'auto';
textContent: string;
onSwitchAutoSave(enabled: boolean): void; onSwitchAutoSave(enabled: boolean): void;
onChangeAutoSaveInterval(interval: number): void; onChangeAutoSaveInterval(interval: number): void;
onChangeAAMZoomMargin(margin: number): void; onChangeAAMZoomMargin(margin: number): void;
@ -38,6 +39,7 @@ interface Props {
onSwitchIntelligentPolygonCrop(enabled: boolean): void; onSwitchIntelligentPolygonCrop(enabled: boolean): void;
onChangeTextFontSize(fontSize: number): void; onChangeTextFontSize(fontSize: number): void;
onChangeTextPosition(position: 'auto' | 'center'): void; onChangeTextPosition(position: 'auto' | 'center'): void;
onChangeTextContent(textContent: string[]): void;
} }
function WorkspaceSettingsComponent(props: Props): JSX.Element { function WorkspaceSettingsComponent(props: Props): JSX.Element {
@ -52,6 +54,7 @@ function WorkspaceSettingsComponent(props: Props): JSX.Element {
defaultApproxPolyAccuracy, defaultApproxPolyAccuracy,
textFontSize, textFontSize,
textPosition, textPosition,
textContent,
onSwitchAutoSave, onSwitchAutoSave,
onChangeAutoSaveInterval, onChangeAutoSaveInterval,
onChangeAAMZoomMargin, onChangeAAMZoomMargin,
@ -62,6 +65,7 @@ function WorkspaceSettingsComponent(props: Props): JSX.Element {
onChangeDefaultApproxPolyAccuracy, onChangeDefaultApproxPolyAccuracy,
onChangeTextFontSize, onChangeTextFontSize,
onChangeTextPosition, onChangeTextPosition,
onChangeTextContent,
} = props; } = props;
const minAutoSaveInterval = 1; const minAutoSaveInterval = 1;
@ -137,6 +141,25 @@ function WorkspaceSettingsComponent(props: Props): JSX.Element {
</Text> </Text>
</Col> </Col>
</Row> </Row>
<Row className='cvat-workspace-settings-text-settings'>
<Col span={24}>
<Text>Content of a text</Text>
</Col>
<Col span={16}>
<Select
className='cvat-workspace-settings-text-content'
mode='multiple'
value={textContent.split(',').filter((entry: string) => !!entry)}
onChange={onChangeTextContent}
>
<Select.Option value='id'>ID</Select.Option>
<Select.Option value='label'>Label</Select.Option>
<Select.Option value='attributes'>Attributes</Select.Option>
<Select.Option value='source'>Source</Select.Option>
<Select.Option value='descriptions'>Descriptions</Select.Option>
</Select>
</Col>
</Row>
<Row className='cvat-workspace-settings-text-settings'> <Row className='cvat-workspace-settings-text-settings'>
<Col span={12}> <Col span={12}>
<Text>Position of a text</Text> <Text>Position of a text</Text>

@ -85,6 +85,7 @@ interface StateToProps {
showObjectsTextAlways: boolean; showObjectsTextAlways: boolean;
textFontSize: number; textFontSize: number;
textPosition: 'auto' | 'center'; textPosition: 'auto' | 'center';
textContent: string;
showAllInterpolationTracks: boolean; showAllInterpolationTracks: boolean;
workspace: Workspace; workspace: Workspace;
minZLayer: number; minZLayer: number;
@ -168,6 +169,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
intelligentPolygonCrop, intelligentPolygonCrop,
textFontSize, textFontSize,
textPosition, textPosition,
textContent,
}, },
shapes: { shapes: {
opacity, colorBy, selectedOpacity, outlined, outlineColor, showBitmap, showProjections, opacity, colorBy, selectedOpacity, outlined, outlineColor, showBitmap, showProjections,
@ -216,6 +218,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
showObjectsTextAlways, showObjectsTextAlways,
textFontSize, textFontSize,
textPosition, textPosition,
textContent,
showAllInterpolationTracks, showAllInterpolationTracks,
curZLayer, curZLayer,
minZLayer, minZLayer,

@ -16,6 +16,7 @@ import {
changeDefaultApproxPolyAccuracy, changeDefaultApproxPolyAccuracy,
switchTextFontSize, switchTextFontSize,
switchTextPosition, switchTextPosition,
switchTextContent,
} from 'actions/settings-actions'; } from 'actions/settings-actions';
import { CombinedState } from 'reducers/interfaces'; import { CombinedState } from 'reducers/interfaces';
@ -33,6 +34,7 @@ interface StateToProps {
intelligentPolygonCrop: boolean; intelligentPolygonCrop: boolean;
textFontSize: number; textFontSize: number;
textPosition: 'auto' | 'center'; textPosition: 'auto' | 'center';
textContent: string;
} }
interface DispatchToProps { interface DispatchToProps {
@ -46,6 +48,7 @@ interface DispatchToProps {
onChangeDefaultApproxPolyAccuracy(approxPolyAccuracy: number): void; onChangeDefaultApproxPolyAccuracy(approxPolyAccuracy: number): void;
onChangeTextFontSize(fontSize: number): void; onChangeTextFontSize(fontSize: number): void;
onChangeTextPosition(position: 'auto' | 'center'): void; onChangeTextPosition(position: 'auto' | 'center'): void;
onChangeTextContent(textContent: string[]): void;
} }
function mapStateToProps(state: CombinedState): StateToProps { function mapStateToProps(state: CombinedState): StateToProps {
@ -61,6 +64,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
defaultApproxPolyAccuracy, defaultApproxPolyAccuracy,
textFontSize, textFontSize,
textPosition, textPosition,
textContent,
} = workspace; } = workspace;
return { return {
@ -74,6 +78,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
defaultApproxPolyAccuracy, defaultApproxPolyAccuracy,
textFontSize, textFontSize,
textPosition, textPosition,
textContent,
}; };
} }
@ -109,6 +114,10 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
onChangeTextPosition(position: 'auto' | 'center'): void { onChangeTextPosition(position: 'auto' | 'center'): void {
dispatch(switchTextPosition(position)); dispatch(switchTextPosition(position));
}, },
onChangeTextContent(textContent: string[]): void {
const serialized = textContent.join(',');
dispatch(switchTextContent(serialized));
},
}; };
} }

@ -642,6 +642,7 @@ export interface WorkspaceSettingsState {
toolsBlockerState: ToolsBlockerState; toolsBlockerState: ToolsBlockerState;
textFontSize: number; textFontSize: number;
textPosition: 'auto' | 'center'; textPosition: 'auto' | 'center';
textContent: string;
} }
export interface ShapesSettingsState { export interface ShapesSettingsState {

@ -34,6 +34,7 @@ const defaultState: SettingsState = {
defaultApproxPolyAccuracy: 9, defaultApproxPolyAccuracy: 9,
textFontSize: 14, textFontSize: 14,
textPosition: 'auto', textPosition: 'auto',
textContent: 'id,source,label,attributes,descriptions',
toolsBlockerState: { toolsBlockerState: {
algorithmsLocked: false, algorithmsLocked: false,
buttonVisible: false, buttonVisible: false,
@ -213,6 +214,16 @@ export default (state = defaultState, action: AnyAction): SettingsState => {
}, },
}; };
} }
case SettingsActionTypes.SWITCH_TEXT_CONTENT: {
const { textContent } = action.payload;
return {
...state,
workspace: {
...state.workspace,
textContent,
},
};
}
case SettingsActionTypes.CHANGE_BRIGHTNESS_LEVEL: { case SettingsActionTypes.CHANGE_BRIGHTNESS_LEVEL: {
return { return {
...state, ...state,

@ -678,12 +678,12 @@ Cypress.Commands.add('checkFrameNum', (frameNum) => {
}); });
Cypress.Commands.add('goToNextFrame', (expectedFrameNum) => { Cypress.Commands.add('goToNextFrame', (expectedFrameNum) => {
cy.get('.cvat-player-next-button').click(); cy.get('.cvat-player-next-button').click().trigger('mouseout');
cy.checkFrameNum(expectedFrameNum); cy.checkFrameNum(expectedFrameNum);
}); });
Cypress.Commands.add('goToPreviousFrame', (expectedFrameNum) => { Cypress.Commands.add('goToPreviousFrame', (expectedFrameNum) => {
cy.get('.cvat-player-previous-button').click(); cy.get('.cvat-player-previous-button').click().trigger('mouseout');
cy.checkFrameNum(expectedFrameNum); cy.checkFrameNum(expectedFrameNum);
}); });

Loading…
Cancel
Save