From b1b89e7e6f7d55ed624ee11d83ae6259e20fe368 Mon Sep 17 00:00:00 2001 From: Kirill Lakhov Date: Wed, 16 Oct 2024 11:38:21 +0300 Subject: [PATCH 01/12] added information about edited state to cvat-ui --- cvat-ui/src/actions/annotation-actions.ts | 11 ++++++++ .../canvas/views/canvas2d/canvas-wrapper.tsx | 26 ++++++++++++++++--- cvat-ui/src/reducers/annotation-reducer.ts | 11 ++++++++ cvat-ui/src/reducers/index.ts | 1 + 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/cvat-ui/src/actions/annotation-actions.ts b/cvat-ui/src/actions/annotation-actions.ts index 9e3eeb8176b..14eff3d6387 100644 --- a/cvat-ui/src/actions/annotation-actions.ts +++ b/cvat-ui/src/actions/annotation-actions.ts @@ -126,6 +126,7 @@ export enum AnnotationActionTypes { COLLAPSE_APPEARANCE = 'COLLAPSE_APPEARANCE', COLLAPSE_OBJECT_ITEMS = 'COLLAPSE_OBJECT_ITEMS', ACTIVATE_OBJECT = 'ACTIVATE_OBJECT', + EDIT_OBJECT = 'EDIT_OBJECT', REMOVE_OBJECT = 'REMOVE_OBJECT', REMOVE_OBJECT_SUCCESS = 'REMOVE_OBJECT_SUCCESS', REMOVE_OBJECT_FAILED = 'REMOVE_OBJECT_FAILED', @@ -242,6 +243,16 @@ export function highlightConflict(conflict: QualityConflict | null): AnyAction { }; } +// TODO: think about better name for this action +export function editObject(objectType: ShapeType | null): AnyAction { + return { + type: AnnotationActionTypes.EDIT_OBJECT, + payload: { + objectType, + }, + }; +} + function wrapAnnotationsInGTJob(states: ObjectState[]): ObjectState[] { return states.map((state: ObjectState) => new Proxy(state, { get(_state, prop) { diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx index e37f9e9b238..fd9c63326e1 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx @@ -45,6 +45,7 @@ import { fetchAnnotationsAsync, getDataFailed, canvasErrorOccurred, + editObject, } from 'actions/annotation-actions'; import { switchGrid, @@ -146,6 +147,7 @@ interface DispatchToProps { onGetDataFailed(error: Error): void; onCanvasErrorOccurred(error: Error): void; onStartIssue(position: number[]): void; + onEditObject(objectType: ShapeType | null): void; } function mapStateToProps(state: CombinedState): StateToProps { @@ -347,6 +349,9 @@ function mapDispatchToProps(dispatch: any): DispatchToProps { onStartIssue(position: number[]): void { dispatch(reviewActions.startIssue(position)); }, + onEditObject(objectType: ShapeType | null): void { + dispatch(editObject(objectType)); + }, }; } @@ -634,6 +639,7 @@ class CanvasWrapperComponent extends React.PureComponent { private onCanvasShapeDrawn = (event: any): void => { const { jobInstance, activeLabelID, activeObjectType, frame, updateActiveControl, onCreateAnnotations, + onEditObject, } = this.props; if (!event.detail.continue) { @@ -669,6 +675,7 @@ class CanvasWrapperComponent extends React.PureComponent { const objectState = new cvat.classes.ObjectState(state); onCreateAnnotations([objectState]); + onEditObject(null); }; private onCanvasObjectsMerged = (event: any): void => { @@ -829,13 +836,21 @@ class CanvasWrapperComponent extends React.PureComponent { } }; - private onCanvasEditStart = (): void => { - const { updateActiveControl } = this.props; + private onCanvasDrawStart = (event: any): void => { + const { onEditObject } = this.props; + onEditObject(event.detail.drawData.shapeType); + }; + + private onCanvasEditStart = (event: any): void => { + const { updateActiveControl, onEditObject } = this.props; updateActiveControl(ActiveControl.EDIT); + onEditObject(event.detail.state.shapeType); }; private onCanvasEditDone = (event: any): void => { - const { activeControl, onUpdateAnnotations, updateActiveControl } = this.props; + const { + activeControl, onUpdateAnnotations, updateActiveControl, onEditObject, + } = this.props; const { state, points, rotation } = event.detail; if (state.rotation !== rotation) { state.rotation = rotation; @@ -848,6 +863,7 @@ class CanvasWrapperComponent extends React.PureComponent { updateActiveControl(ActiveControl.CURSOR); } onUpdateAnnotations([state]); + onEditObject(null); }; private onCanvasSliceDone = (event: any): void => { @@ -887,8 +903,9 @@ class CanvasWrapperComponent extends React.PureComponent { }; private onCanvasCancel = (): void => { - const { onResetCanvas } = this.props; + const { onResetCanvas, onEditObject } = this.props; onResetCanvas(); + onEditObject(null); }; private onCanvasFindObject = async (e: any): Promise => { @@ -1040,6 +1057,7 @@ class CanvasWrapperComponent extends React.PureComponent { canvasInstance.html().addEventListener('mousedown', this.onCanvasMouseDown); canvasInstance.html().addEventListener('click', this.onCanvasClicked); + canvasInstance.html().addEventListener('canvas.drawstart', this.onCanvasDrawStart); canvasInstance.html().addEventListener('canvas.editstart', this.onCanvasEditStart); canvasInstance.html().addEventListener('canvas.edited', this.onCanvasEditDone); canvasInstance.html().addEventListener('canvas.sliced', this.onCanvasSliceDone); diff --git a/cvat-ui/src/reducers/annotation-reducer.ts b/cvat-ui/src/reducers/annotation-reducer.ts index 847a0b84d93..15837f87a3e 100644 --- a/cvat-ui/src/reducers/annotation-reducer.ts +++ b/cvat-ui/src/reducers/annotation-reducer.ts @@ -98,6 +98,7 @@ const defaultState: AnnotationState = { activatedStateID: null, activatedElementID: null, activatedAttributeID: null, + editedState: null, highlightedConflict: null, saving: { forceExit: false, @@ -622,6 +623,16 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { }, }; } + case AnnotationActionTypes.EDIT_OBJECT: { + const { objectType } = action.payload; + return { + ...state, + annotations: { + ...state.annotations, + editedState: objectType, + }, + }; + } case AnnotationActionTypes.REMOVE_OBJECT: { const { objectState, force } = action.payload; return { diff --git a/cvat-ui/src/reducers/index.ts b/cvat-ui/src/reducers/index.ts index 999d7d6c541..2508c83a31b 100644 --- a/cvat-ui/src/reducers/index.ts +++ b/cvat-ui/src/reducers/index.ts @@ -770,6 +770,7 @@ export interface AnnotationState { activatedStateID: number | null; activatedElementID: number | null; activatedAttributeID: number | null; + editedState: ShapeType | null; highlightedConflict: QualityConflict | null; collapsed: Record; collapsedAll: boolean; From dc04778e01e16c8b7fd38503969e88af75c21cb0 Mon Sep 17 00:00:00 2001 From: Kirill Lakhov Date: Wed, 16 Oct 2024 17:39:12 +0300 Subject: [PATCH 02/12] hide mask on shortcut --- cvat-canvas/src/typescript/canvasModel.ts | 6 +++ cvat-canvas/src/typescript/masksHandler.ts | 29 +++++++++++-- cvat-ui/src/actions/annotation-actions.ts | 39 ++++++++++++++--- .../canvas/views/canvas2d/canvas-wrapper.tsx | 33 ++++++++------ .../objects-side-bar/objects-list.tsx | 17 ++++++++ cvat-ui/src/reducers/annotation-reducer.ts | 43 +++++++++++++++++-- cvat-ui/src/reducers/index.ts | 7 ++- 7 files changed, 146 insertions(+), 28 deletions(-) diff --git a/cvat-canvas/src/typescript/canvasModel.ts b/cvat-canvas/src/typescript/canvasModel.ts index 2c7a1f08d20..0ad62484c14 100644 --- a/cvat-canvas/src/typescript/canvasModel.ts +++ b/cvat-canvas/src/typescript/canvasModel.ts @@ -96,6 +96,7 @@ export interface Configuration { controlPointsSize?: number; outlinedBorders?: string | false; resetZoom?: boolean; + hideEditedObject?: boolean; } export interface BrushTool { @@ -416,6 +417,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel { textPosition: consts.DEFAULT_SHAPE_TEXT_POSITION, textContent: consts.DEFAULT_SHAPE_TEXT_CONTENT, undefinedAttrValue: consts.DEFAULT_UNDEFINED_ATTR_VALUE, + hideEditedObject: false, }, imageBitmap: false, image: null, @@ -981,6 +983,10 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel { this.data.configuration.CSSImageFilter = configuration.CSSImageFilter; } + if (typeof configuration.hideEditedObject === 'boolean') { + this.data.configuration.hideEditedObject = configuration.hideEditedObject; + } + this.notify(UpdateReasons.CONFIG_UPDATED); } diff --git a/cvat-canvas/src/typescript/masksHandler.ts b/cvat-canvas/src/typescript/masksHandler.ts index cdaa4d86d2f..7b1080977ab 100644 --- a/cvat-canvas/src/typescript/masksHandler.ts +++ b/cvat-canvas/src/typescript/masksHandler.ts @@ -65,6 +65,7 @@ export class MasksHandlerImpl implements MasksHandler { private startTimestamp: number; private geometry: Geometry; private drawingOpacity: number; + private isHidden: boolean; private keepDrawnPolygon(): void { const canvasWrapper = this.canvas.getElement().parentElement; @@ -217,12 +218,22 @@ export class MasksHandlerImpl implements MasksHandler { private imageDataFromCanvas(wrappingBBox: WrappingBBox): Uint8ClampedArray { const imageData = this.canvas.toCanvasElement() .getContext('2d').getImageData( - wrappingBBox.left, wrappingBBox.top, - wrappingBBox.right - wrappingBBox.left + 1, wrappingBBox.bottom - wrappingBBox.top + 1, + wrappingBBox.left, + wrappingBBox.top, + wrappingBBox.right - wrappingBBox.left + 1, + wrappingBBox.bottom - wrappingBBox.top + 1, ).data; return imageData; } + private updateHidden(value: boolean) { + if (value) { + this.canvas.getElement().parentElement.style.display = 'none'; + } else { + this.canvas.getElement().parentElement.style.display = 'block'; + } + } + private updateBrushTools(brushTool?: BrushTool, opts: Partial = {}): void { if (this.isPolygonDrawing) { // tool was switched from polygon to brush for example @@ -530,6 +541,10 @@ export class MasksHandlerImpl implements MasksHandler { public configurate(configuration: Configuration): void { this.colorBy = configuration.colorBy; + + if (this.isHidden !== configuration.hideEditedObject) { + this.updateHidden(configuration.hideEditedObject); + } } public transform(geometry: Geometry): void { @@ -563,7 +578,10 @@ export class MasksHandlerImpl implements MasksHandler { const color = fabric.Color.fromHex(this.getStateColor(drawData.initialState)).getSource(); const [left, top, right, bottom] = points.slice(-4); const imageBitmap = expandChannels(color[0], color[1], color[2], points); - imageDataToDataURL(imageBitmap, right - left + 1, bottom - top + 1, + imageDataToDataURL( + imageBitmap, + right - left + 1, + bottom - top + 1, (dataURL: string) => new Promise((resolve) => { fabric.Image.fromURL(dataURL, (image: fabric.Image) => { try { @@ -654,7 +672,10 @@ export class MasksHandlerImpl implements MasksHandler { const color = fabric.Color.fromHex(this.getStateColor(editData.state)).getSource(); const [left, top, right, bottom] = points.slice(-4); const imageBitmap = expandChannels(color[0], color[1], color[2], points); - imageDataToDataURL(imageBitmap, right - left + 1, bottom - top + 1, + imageDataToDataURL( + imageBitmap, + right - left + 1, + bottom - top + 1, (dataURL: string) => new Promise((resolve) => { fabric.Image.fromURL(dataURL, (image: fabric.Image) => { try { diff --git a/cvat-ui/src/actions/annotation-actions.ts b/cvat-ui/src/actions/annotation-actions.ts index 14eff3d6387..ae7f1716a86 100644 --- a/cvat-ui/src/actions/annotation-actions.ts +++ b/cvat-ui/src/actions/annotation-actions.ts @@ -126,7 +126,9 @@ export enum AnnotationActionTypes { COLLAPSE_APPEARANCE = 'COLLAPSE_APPEARANCE', COLLAPSE_OBJECT_ITEMS = 'COLLAPSE_OBJECT_ITEMS', ACTIVATE_OBJECT = 'ACTIVATE_OBJECT', - EDIT_OBJECT = 'EDIT_OBJECT', + UPDATE_EDITED_STATE = 'UPDATE_EDITED_STATE', + HIDE_EDITED_STATE = 'HIDE_EDITED_STATE', + RESET_EDITED_STATE = 'RESET_EDITED_STATE', REMOVE_OBJECT = 'REMOVE_OBJECT', REMOVE_OBJECT_SUCCESS = 'REMOVE_OBJECT_SUCCESS', REMOVE_OBJECT_FAILED = 'REMOVE_OBJECT_FAILED', @@ -243,16 +245,43 @@ export function highlightConflict(conflict: QualityConflict | null): AnyAction { }; } -// TODO: think about better name for this action -export function editObject(objectType: ShapeType | null): AnyAction { +export function updateEditedState(shapeType: ShapeType | null, editedState: ObjectState | null): AnyAction { return { - type: AnnotationActionTypes.EDIT_OBJECT, + type: AnnotationActionTypes.UPDATE_EDITED_STATE, payload: { - objectType, + shapeType, + editedState, }, }; } +export function resetEditedState(): AnyAction { + return { + type: AnnotationActionTypes.RESET_EDITED_STATE, + payload: {}, + }; +} + +// TODO: change to regular func, we dont need async +export function hideEditedState(hide: boolean): ThunkAction { + return async (dispatch: ThunkDispatch, getState): Promise => { + const state = getState(); + const { instance: canvas } = state.annotation.canvas; + if (canvas) { + (canvas as Canvas).configure({ + hideEditedObject: hide, + }); + } + + dispatch({ + type: AnnotationActionTypes.HIDE_EDITED_STATE, + payload: { + hide, + }, + }); + }; +} + function wrapAnnotationsInGTJob(states: ObjectState[]): ObjectState[] { return states.map((state: ObjectState) => new Proxy(state, { get(_state, prop) { diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx index fd9c63326e1..d861745f4af 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/canvas-wrapper.tsx @@ -45,7 +45,8 @@ import { fetchAnnotationsAsync, getDataFailed, canvasErrorOccurred, - editObject, + updateEditedState, + resetEditedState, } from 'actions/annotation-actions'; import { switchGrid, @@ -147,7 +148,8 @@ interface DispatchToProps { onGetDataFailed(error: Error): void; onCanvasErrorOccurred(error: Error): void; onStartIssue(position: number[]): void; - onEditObject(objectType: ShapeType | null): void; + onUpdateEditedObject(objectType: ShapeType | null, editedState: ObjectState | null): void; + onResetEditedObject(): void; } function mapStateToProps(state: CombinedState): StateToProps { @@ -349,8 +351,11 @@ function mapDispatchToProps(dispatch: any): DispatchToProps { onStartIssue(position: number[]): void { dispatch(reviewActions.startIssue(position)); }, - onEditObject(objectType: ShapeType | null): void { - dispatch(editObject(objectType)); + onUpdateEditedObject(objectType: ShapeType | null, editedState: ObjectState | null): void { + dispatch(updateEditedState(objectType, editedState)); + }, + onResetEditedObject(): void { + dispatch(resetEditedState()); }, }; } @@ -639,7 +644,7 @@ class CanvasWrapperComponent extends React.PureComponent { private onCanvasShapeDrawn = (event: any): void => { const { jobInstance, activeLabelID, activeObjectType, frame, updateActiveControl, onCreateAnnotations, - onEditObject, + onResetEditedObject, } = this.props; if (!event.detail.continue) { @@ -675,7 +680,7 @@ class CanvasWrapperComponent extends React.PureComponent { const objectState = new cvat.classes.ObjectState(state); onCreateAnnotations([objectState]); - onEditObject(null); + onResetEditedObject(); }; private onCanvasObjectsMerged = (event: any): void => { @@ -837,19 +842,19 @@ class CanvasWrapperComponent extends React.PureComponent { }; private onCanvasDrawStart = (event: any): void => { - const { onEditObject } = this.props; - onEditObject(event.detail.drawData.shapeType); + const { onUpdateEditedObject } = this.props; + onUpdateEditedObject(event.detail.drawData.shapeType, null); }; private onCanvasEditStart = (event: any): void => { - const { updateActiveControl, onEditObject } = this.props; + const { updateActiveControl, onUpdateEditedObject } = this.props; updateActiveControl(ActiveControl.EDIT); - onEditObject(event.detail.state.shapeType); + onUpdateEditedObject(event.detail.state.shapeType, event.detail.state); }; private onCanvasEditDone = (event: any): void => { const { - activeControl, onUpdateAnnotations, updateActiveControl, onEditObject, + activeControl, onUpdateAnnotations, updateActiveControl, onResetEditedObject, } = this.props; const { state, points, rotation } = event.detail; if (state.rotation !== rotation) { @@ -863,7 +868,7 @@ class CanvasWrapperComponent extends React.PureComponent { updateActiveControl(ActiveControl.CURSOR); } onUpdateAnnotations([state]); - onEditObject(null); + onResetEditedObject(); }; private onCanvasSliceDone = (event: any): void => { @@ -903,9 +908,9 @@ class CanvasWrapperComponent extends React.PureComponent { }; private onCanvasCancel = (): void => { - const { onResetCanvas, onEditObject } = this.props; + const { onResetCanvas, onResetEditedObject } = this.props; onResetCanvas(); - onEditObject(null); + onResetEditedObject(); }; private onCanvasFindObject = async (e: any): Promise => { diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/objects-list.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/objects-list.tsx index 7f120cc981d..68a207fe708 100644 --- a/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/objects-list.tsx +++ b/cvat-ui/src/containers/annotation-page/standard-workspace/objects-side-bar/objects-list.tsx @@ -19,6 +19,7 @@ import { switchPropagateVisibility as switchPropagateVisibilityAction, removeObject as removeObjectAction, fetchAnnotationsAsync, + hideEditedState, } from 'actions/annotation-actions'; import { changeShowGroundTruth as changeShowGroundTruthAction, @@ -56,6 +57,11 @@ interface StateToProps { normalizedKeyMap: Record; showGroundTruth: boolean; workspace: Workspace; + editedState: { + shapeType: ShapeType | null; + editedState: ObjectState | null; + editedStateHidden: boolean; + }, } interface DispatchToProps { @@ -67,6 +73,7 @@ interface DispatchToProps { changeFrame(frame: number): void; changeGroupColor(group: number, color: string): void; changeShowGroundTruth(value: boolean): void; + changeHideEditedState(value: boolean): void; } const componentShortcuts = { @@ -180,6 +187,7 @@ function mapStateToProps(state: CombinedState): StateToProps { collapsedAll, activatedStateID, activatedElementID, + edited, zLayer: { min: minZLayer, max: maxZLayer }, }, job: { instance: jobInstance }, @@ -233,6 +241,7 @@ function mapStateToProps(state: CombinedState): StateToProps { normalizedKeyMap, showGroundTruth, workspace, + editedState: edited, }; } @@ -263,6 +272,9 @@ function mapDispatchToProps(dispatch: any): DispatchToProps { dispatch(changeShowGroundTruthAction(value)); dispatch(fetchAnnotationsAsync()); }, + changeHideEditedState(value: boolean): void { + dispatch(hideEditedState(value)); + }, }; } @@ -475,6 +487,11 @@ class ObjectsListContainer extends React.PureComponent { SWITCH_HIDDEN: (event: KeyboardEvent | undefined) => { preventDefault(event); const state = activatedState(); + const { editedState, changeHideEditedState } = this.props; + console.log(editedState); + if (editedState.shapeType === ShapeType.MASK) { + changeHideEditedState(!editedState.editedStateHidden); + } if (state) { state.hidden = !state.hidden; updateAnnotations([state]); diff --git a/cvat-ui/src/reducers/annotation-reducer.ts b/cvat-ui/src/reducers/annotation-reducer.ts index 15837f87a3e..2a97edb3459 100644 --- a/cvat-ui/src/reducers/annotation-reducer.ts +++ b/cvat-ui/src/reducers/annotation-reducer.ts @@ -98,7 +98,11 @@ const defaultState: AnnotationState = { activatedStateID: null, activatedElementID: null, activatedAttributeID: null, - editedState: null, + edited: { + shapeType: null, + editedState: null, + editedStateHidden: false, + }, highlightedConflict: null, saving: { forceExit: false, @@ -623,13 +627,44 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { }, }; } - case AnnotationActionTypes.EDIT_OBJECT: { - const { objectType } = action.payload; + case AnnotationActionTypes.RESET_EDITED_STATE: { + return { + ...state, + annotations: { + ...state.annotations, + edited: { + ...state.annotations.edited, + shapeType: null, + editedState: null, + editedStateHidden: false, + }, + }, + }; + } + case AnnotationActionTypes.UPDATE_EDITED_STATE: { + const { shapeType, editedState } = action.payload; return { ...state, annotations: { ...state.annotations, - editedState: objectType, + edited: { + ...state.annotations.edited, + shapeType: (shapeType ?? null), + editedState: (editedState ?? null), + }, + }, + }; + } + case AnnotationActionTypes.HIDE_EDITED_STATE: { + const { hide } = action.payload; + return { + ...state, + annotations: { + ...state.annotations, + edited: { + ...state.annotations.edited, + editedStateHidden: hide, + }, }, }; } diff --git a/cvat-ui/src/reducers/index.ts b/cvat-ui/src/reducers/index.ts index 2508c83a31b..65b87d0e887 100644 --- a/cvat-ui/src/reducers/index.ts +++ b/cvat-ui/src/reducers/index.ts @@ -9,6 +9,7 @@ import { Webhook, MLModel, Organization, Job, Task, Project, Label, User, QualityConflict, FramesMetaData, RQStatus, Event, Invitation, SerializedAPISchema, Request, TargetMetric, ValidationLayout, + ObjectState, } from 'cvat-core-wrapper'; import { IntelligentScissors } from 'utils/opencv-wrapper/intelligent-scissors'; import { KeyMap, KeyMapItem } from 'utils/mousetrap-react'; @@ -770,7 +771,11 @@ export interface AnnotationState { activatedStateID: number | null; activatedElementID: number | null; activatedAttributeID: number | null; - editedState: ShapeType | null; + edited: { + shapeType: ShapeType | null; + editedState: ObjectState | null; + editedStateHidden: boolean; + }; highlightedConflict: QualityConflict | null; collapsed: Record; collapsedAll: boolean; From 65a13b219b9d3520bd6f64440f51711626f6d57f Mon Sep 17 00:00:00 2001 From: Kirill Lakhov Date: Thu, 17 Oct 2024 11:33:19 +0300 Subject: [PATCH 03/12] fixed missing cursor --- cvat-canvas/src/typescript/masksHandler.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cvat-canvas/src/typescript/masksHandler.ts b/cvat-canvas/src/typescript/masksHandler.ts index 7b1080977ab..ca32a086e78 100644 --- a/cvat-canvas/src/typescript/masksHandler.ts +++ b/cvat-canvas/src/typescript/masksHandler.ts @@ -227,10 +227,12 @@ export class MasksHandlerImpl implements MasksHandler { } private updateHidden(value: boolean) { + this.isHidden = value; if (value) { this.canvas.getElement().parentElement.style.display = 'none'; } else { - this.canvas.getElement().parentElement.style.display = 'block'; + this.canvas.getElement().parentElement.style.display = this.isDrawing || this.isEditing ? 'block' : ''; + // TODO: change brush tool position to avoid flickering } } From 0684a9ae98b4b9f485cdf9e9ec6238c96df98f73 Mon Sep 17 00:00:00 2001 From: Kirill Lakhov Date: Thu, 17 Oct 2024 11:43:43 +0300 Subject: [PATCH 04/12] add hide icon --- .../canvas/views/canvas2d/brush-tools.tsx | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/brush-tools.tsx b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/brush-tools.tsx index 6c140438c20..77f00efc464 100644 --- a/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/brush-tools.tsx +++ b/cvat-ui/src/components/annotation-page/canvas/views/canvas2d/brush-tools.tsx @@ -8,7 +8,7 @@ import React, { useCallback, useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; import { useDispatch, useSelector } from 'react-redux'; import Button from 'antd/lib/button'; -import Icon, { VerticalAlignBottomOutlined } from '@ant-design/icons'; +import Icon, { EyeInvisibleFilled, EyeOutlined, VerticalAlignBottomOutlined } from '@ant-design/icons'; import InputNumber from 'antd/lib/input-number'; import Select from 'antd/lib/select'; import notification from 'antd/lib/notification'; @@ -23,7 +23,7 @@ import { import CVATTooltip from 'components/common/cvat-tooltip'; import { CombinedState, ObjectType, ShapeType } from 'reducers'; import LabelSelector from 'components/label-selector/label-selector'; -import { rememberObject, updateCanvasBrushTools } from 'actions/annotation-actions'; +import { hideEditedState, rememberObject, updateCanvasBrushTools } from 'actions/annotation-actions'; import { ShortcutScope } from 'utils/enums'; import GlobalHotKeys from 'utils/mousetrap-react'; import { subKeyMap } from 'utils/component-subkeymap'; @@ -75,6 +75,7 @@ function BrushTools(): React.ReactPortal | null { const config = useSelector((state: CombinedState) => state.annotation.canvas.brushTools); const canvasInstance = useSelector((state: CombinedState) => state.annotation.canvas.instance); const labels = useSelector((state: CombinedState) => state.annotation.job.labels); + const editedState = useSelector((state: CombinedState) => state.annotation.annotations.edited); const { keyMap, normalizedKeyMap } = useSelector((state: CombinedState) => state.shortcuts); const { visible } = config; @@ -103,6 +104,10 @@ function BrushTools(): React.ReactPortal | null { } }, [setCurrentTool, blockedTools['polygon-minus']]); + const hideMask = useCallback((hide: boolean) => { + dispatch(hideEditedState(hide)); + }, [dispatch]); + const handlers: Record void> = { ACTIVATE_BRUSH_TOOL_STANDARD_CONTROLS: setBrushTool, ACTIVATE_ERASER_TOOL_STANDARD_CONTROLS: setEraserTool, @@ -365,6 +370,17 @@ function BrushTools(): React.ReactPortal | null { icon={} onClick={() => setRemoveUnderlyingPixels(!removeUnderlyingPixels)} /> + { + editedState && editedState.shapeType === ShapeType.MASK && ( +