feat(devtool): ImageAnnotation 中支持修改现有定义的标注类型
This commit is contained in:
parent
cc73188637
commit
7bd921b51c
|
@ -5,6 +5,12 @@ export interface PropertyRenderBase {
|
|||
required?: boolean,
|
||||
}
|
||||
|
||||
type SelectOption<T extends string> = {
|
||||
value: T,
|
||||
options: Array<{ value: T, label: string }>,
|
||||
onChange: (value: T) => void
|
||||
}
|
||||
|
||||
interface PropertyRenderInputOptions {
|
||||
text: {
|
||||
value: string,
|
||||
|
@ -17,7 +23,8 @@ interface PropertyRenderInputOptions {
|
|||
'long-text': {
|
||||
value: string,
|
||||
onChange: (value: string) => void
|
||||
}
|
||||
},
|
||||
select: SelectOption<string>
|
||||
}
|
||||
type RenderType = keyof PropertyRenderInputOptions;
|
||||
|
||||
|
@ -162,6 +169,21 @@ const PropertyGrid: React.FC<PropertyGridProps> = ({ properties, titleColumnWidt
|
|||
} else if (type === 'long-text') {
|
||||
const propertyLongText = property.render as PropertyRenderInputOptions['long-text'];
|
||||
field = <textarea value={propertyLongText.value} onChange={(e) => propertyLongText.onChange(e.target.value)} />;
|
||||
} else if (type === 'select') {
|
||||
const propertySelect = property.render as PropertyRenderInputOptions['select'];
|
||||
field = (
|
||||
<select
|
||||
value={propertySelect.value}
|
||||
onChange={(e) => propertySelect.onChange(e.target.value as any)}
|
||||
style={{ width: '100%', padding: '4px' }}
|
||||
>
|
||||
{propertySelect.options.map(option => (
|
||||
<option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
console.error('Invalid property render type:', property.render);
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { useState } from "react";
|
||||
import { Annotation } from "../components/ImageEditor/types";
|
||||
import { useImmer } from "use-immer";
|
||||
|
||||
export type DefinitionType = 'template' | 'ocr' | 'color' | 'hint-box' | 'hint-point';
|
||||
|
||||
export interface Definition {
|
||||
export interface BaseDefinition {
|
||||
/** 最终出现在 R.py 中的名称 */
|
||||
name: string;
|
||||
/** 显示在调试器与调试输出中的名称 */
|
||||
|
@ -17,7 +16,7 @@ export interface Definition {
|
|||
}
|
||||
|
||||
|
||||
export interface TemplateDefinition extends Definition {
|
||||
export interface TemplateDefinition extends BaseDefinition {
|
||||
type: 'template';
|
||||
/**
|
||||
* 是否将这个模板的矩形范围作为运行时
|
||||
|
@ -29,6 +28,15 @@ export interface TemplateDefinition extends Definition {
|
|||
useHintRect: boolean
|
||||
}
|
||||
|
||||
export interface HintBoxDefinition extends BaseDefinition {
|
||||
type: 'hint-box';
|
||||
}
|
||||
|
||||
export interface HintPointDefinition extends BaseDefinition {
|
||||
type: 'hint-point';
|
||||
}
|
||||
|
||||
export type Definition = TemplateDefinition | HintBoxDefinition | HintPointDefinition;
|
||||
|
||||
export type Definitions = Record<string, Definition>;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import PropertyGrid, { Property, PropertyCategory } from '../../components/Prope
|
|||
import ImageEditor, { AnnotationChangedEvent } from '../../components/ImageEditor/ImageEditor';
|
||||
import { Annotation, Tool as EditorTool } from '../../components/ImageEditor/types';
|
||||
import { BsCursor, BsFolder2Open, BsFloppy, BsCardImage, BsQuestionSquare, BsPinMap } from 'react-icons/bs';
|
||||
import useImageMetaData, { DefinitionType, ImageMetaData, TemplateDefinition, Definitions } from '../../hooks/useImageMetaData';
|
||||
import useImageMetaData, { DefinitionType, ImageMetaData, TemplateDefinition, Definitions, Definition } from '../../hooks/useImageMetaData';
|
||||
import { useImageViewerModal } from '../../components/ImageViewerModal';
|
||||
import { useMessageBox } from '../../hooks/useMessageBox';
|
||||
import { useToast } from '../../components/ToastMessage';
|
||||
|
@ -138,7 +138,7 @@ const usePropertyGridData = (
|
|||
definitions: Definitions,
|
||||
image: HTMLImageElement | null,
|
||||
onImageClick: (imageUrl: string) => void,
|
||||
onDefinitionChange?: (id: string, changes: Partial<TemplateDefinition>) => void,
|
||||
onDefinitionChange?: (id: string, changes: Partial<Definition>) => void,
|
||||
imageFileName?: string,
|
||||
annotations?: Annotation[],
|
||||
currentFileResult?: FileResult | null
|
||||
|
@ -246,7 +246,25 @@ const usePropertyGridData = (
|
|||
},
|
||||
{
|
||||
title: '类型',
|
||||
render: () => definition.type,
|
||||
render: {
|
||||
type: 'select',
|
||||
required: true,
|
||||
value: definition.type,
|
||||
options: selectedAnnotation.type === 'rect'
|
||||
? [
|
||||
{ value: 'template', label: '模板' },
|
||||
{ value: 'hint-box', label: 'HintBox' }
|
||||
]
|
||||
: [
|
||||
{ value: 'hint-point', label: 'HintPoint' }
|
||||
],
|
||||
onChange: (value) => {
|
||||
if (value === definition.type) return;
|
||||
onDefinitionChange?.(selectedAnnotation.id, {
|
||||
type: value as "template" | "hint-box" | "hint-point",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
foldable: true
|
||||
|
@ -540,7 +558,7 @@ const ImageAnnotation: React.FC = () => {
|
|||
setSelectedAnnotation(annotation);
|
||||
};
|
||||
|
||||
const handleDefinitionChange = (id: string, changes: Partial<TemplateDefinition>) => {
|
||||
const handleDefinitionChange = (id: string, changes: Partial<Definition>) => {
|
||||
Definitions.update({
|
||||
...changes,
|
||||
annotationId: id
|
||||
|
|
|
@ -9,7 +9,7 @@ import { Splitable } from '../../components/Splitable';
|
|||
import { Tool, Annotation } from '../../components/ImageEditor/types';
|
||||
import { create } from 'zustand';
|
||||
import { css } from '@emotion/react';
|
||||
import useImageMetaData, { Definition, DefinitionType, ImageMetaData, TemplateDefinition } from '../../hooks/useImageMetaData';
|
||||
import useImageMetaData, { BaseDefinition, DefinitionType, ImageMetaData, TemplateDefinition } from '../../hooks/useImageMetaData';
|
||||
import { useDarkMode } from '../../hooks/useDarkMode';
|
||||
import { useDebugClient } from '../../store/debugStore';
|
||||
import useLatestCallback from '../../hooks/useLatestCallback';
|
||||
|
@ -157,25 +157,25 @@ const useScriptRecorderStore = create<ScriptRecorderState>((set) => ({
|
|||
}));
|
||||
|
||||
interface ToolConfigItem {
|
||||
code?: (d: Definition, a: Annotation) => string;
|
||||
code?: (d: BaseDefinition, a: Annotation) => string;
|
||||
}
|
||||
|
||||
const ToolConfig: Record<ScriptRecorderTool, ToolConfigItem> = {
|
||||
'drag': {
|
||||
},
|
||||
'template': {
|
||||
code: (d: Definition) => `image.find(R.${d.name})`,
|
||||
code: (d: BaseDefinition) => `image.find(R.${d.name})`,
|
||||
|
||||
},
|
||||
'template-click': {
|
||||
code: (d: Definition) =>
|
||||
code: (d: BaseDefinition) =>
|
||||
`if image.find(R.${d.name}):\n\tdevice.click()`,
|
||||
},
|
||||
'ocr': {
|
||||
code: (d: Definition) => `ocr.ocr(R.${d.name})`,
|
||||
code: (d: BaseDefinition) => `ocr.ocr(R.${d.name})`,
|
||||
},
|
||||
'ocr-click': {
|
||||
code: (d: Definition) =>
|
||||
code: (d: BaseDefinition) =>
|
||||
`if ocr.ocr(R.${d.name}):\n\tdevice.click()`,
|
||||
},
|
||||
'hint-box': {
|
||||
|
|
Loading…
Reference in New Issue