feat(devtool): ImageAnnotation 新增 description 字段
用于给标注添加描述,描述文本会进入 R.py 的注释中
This commit is contained in:
parent
79927a7b7a
commit
425057d3ef
|
@ -13,6 +13,10 @@ interface PropertyRenderInputOptions {
|
|||
checkbox: {
|
||||
value: boolean,
|
||||
onChange: (value: boolean) => void
|
||||
},
|
||||
'long-text': {
|
||||
value: string,
|
||||
onChange: (value: string) => void
|
||||
}
|
||||
}
|
||||
type RenderType = keyof PropertyRenderInputOptions;
|
||||
|
@ -70,6 +74,18 @@ const PropertyContent = styled.div`
|
|||
min-height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
min-height: 80px;
|
||||
resize: vertical;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
width: 100%;
|
||||
padding: 4px;
|
||||
}
|
||||
`;
|
||||
|
||||
const FullWidthPropertyContent = styled(PropertyContent)`
|
||||
|
@ -143,6 +159,9 @@ const PropertyGrid: React.FC<PropertyGridProps> = ({ properties, titleColumnWidt
|
|||
} else if (type === 'checkbox') {
|
||||
const propertyCheckbox = property.render as PropertyRenderInputOptions['checkbox'];
|
||||
field = <input type="checkbox" checked={propertyCheckbox.value} onChange={(e) => propertyCheckbox.onChange(e.target.checked)} />;
|
||||
} 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 {
|
||||
console.error('Invalid property render type:', property.render);
|
||||
|
|
|
@ -9,6 +9,8 @@ export interface Definition {
|
|||
name: string;
|
||||
/** 显示在调试器与调试输出中的名称 */
|
||||
displayName: string;
|
||||
/** 描述信息 */
|
||||
description: string;
|
||||
type: DefinitionType;
|
||||
/** 标注 ID */
|
||||
annotationId: string;
|
||||
|
@ -52,8 +54,6 @@ function toString(data: ImageMetaData): string {
|
|||
|
||||
function useImageMetaData(data?: ImageMetaData) {
|
||||
const [imageMetaData, updateImageMetaData] = useImmer<ImageMetaData>(data || {
|
||||
|
||||
|
||||
definitions: {},
|
||||
annotations: [],
|
||||
});
|
||||
|
|
|
@ -235,6 +235,15 @@ const usePropertyGridData = (
|
|||
onChange: (value: string) => onDefinitionChange?.(selectedAnnotation.id, { displayName: value }),
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
render: {
|
||||
type: 'long-text',
|
||||
required: false,
|
||||
value: definition.description || '',
|
||||
onChange: (value: string) => onDefinitionChange?.(selectedAnnotation.id, { description: value }),
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
render: () => definition.type,
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"definitions":{"be6836bd-ee42-432b-9166-469c74f32f0b":{"name":"InPurodyuusu.BoxWeeksUntilExam","displayName":"培育中下次考试剩余周数","type":"hint-box","annotationId":"be6836bd-ee42-432b-9166-469c74f32f0b","useHintRect":false}},"annotations":[{"id":"be6836bd-ee42-432b-9166-469c74f32f0b","type":"rect","data":{"x1":11,"y1":8,"x2":237,"y2":196}}]}
|
||||
{"definitions":{"be6836bd-ee42-432b-9166-469c74f32f0b":{"name":"InPurodyuusu.BoxWeeksUntilExam","displayName":"考试剩余周","type":"hint-box","annotationId":"be6836bd-ee42-432b-9166-469c74f32f0b","useHintRect":false,"description":"培育中左上角的下次考试剩余周数"}},"annotations":[{"id":"be6836bd-ee42-432b-9166-469c74f32f0b","type":"rect","data":{"x1":11,"y1":8,"x2":237,"y2":196}}]}
|
|
@ -6,7 +6,7 @@ import shutil
|
|||
import uuid
|
||||
import jinja2
|
||||
import argparse
|
||||
from typing import Any, TypeGuard, Literal, Union, cast
|
||||
from typing import Any, Optional, TypeGuard, Literal, Union, cast
|
||||
from dataclasses import dataclass
|
||||
from dataclasses_json import dataclass_json, DataClassJsonMixin
|
||||
|
||||
|
@ -22,6 +22,8 @@ SpriteType = Literal['basic', 'metadata']
|
|||
class Resource:
|
||||
type: Literal['template', 'hint-box', 'hint-point']
|
||||
data: 'Sprite | HintBox | HintPoint'
|
||||
description: str
|
||||
"""资源的描述信息"""
|
||||
|
||||
@dataclass
|
||||
class Sprite:
|
||||
|
@ -102,6 +104,8 @@ class Definition(DataClassJsonMixin):
|
|||
"""标注类型"""
|
||||
annotationId: str
|
||||
"""标注 ID"""
|
||||
description: Optional[str] = None
|
||||
"""描述信息"""
|
||||
|
||||
class TemplateDefinition(Definition):
|
||||
"""模板匹配类型的资源定义"""
|
||||
|
@ -166,7 +170,7 @@ def load_metadata(root_path: str, png_file: str) -> list[Resource]:
|
|||
"""加载 metadata 类型的标注"""
|
||||
json_path = png_file + '.json'
|
||||
with open(json_path, 'r', encoding='utf-8') as f:
|
||||
metadata = SpriteMetadata.from_json(f.read()) # 使用 dataclass-json 的解析方法
|
||||
metadata = SpriteMetadata.from_json(f.read())
|
||||
# 遍历标注,裁剪、保存图片
|
||||
clips: dict[str, str] = {} # id -> 文件路径
|
||||
image = cv2.imread(png_file)
|
||||
|
@ -196,12 +200,11 @@ def load_metadata(root_path: str, png_file: str) -> list[Resource]:
|
|||
name=definition.name.split('.')[-1],
|
||||
display_name=definition.displayName,
|
||||
class_path=definition.name.split('.')[:-1],
|
||||
|
||||
rel_path=png_file,
|
||||
abs_path=os.path.abspath(clips[definition.annotationId]),
|
||||
origin_file=os.path.abspath(png_file),
|
||||
)
|
||||
resources.append(Resource('template', spr))
|
||||
resources.append(Resource('template', spr, definition.description or ''))
|
||||
elif definition.type == 'hint-box':
|
||||
annotation = query_annotation(metadata.annotations, definition.annotationId)
|
||||
rect = annotation.data
|
||||
|
@ -216,7 +219,7 @@ def load_metadata(root_path: str, png_file: str) -> list[Resource]:
|
|||
y2=rect.y2,
|
||||
origin_file=os.path.abspath(png_file),
|
||||
)
|
||||
resources.append(Resource('hint-box', hb))
|
||||
resources.append(Resource('hint-box', hb, definition.description or ''))
|
||||
elif definition.type == 'hint-point':
|
||||
annotation = query_annotation(metadata.annotations, definition.annotationId)
|
||||
pt = annotation.data
|
||||
|
@ -229,7 +232,7 @@ def load_metadata(root_path: str, png_file: str) -> list[Resource]:
|
|||
class_path=definition.name.split('.')[:-1],
|
||||
origin_file=os.path.abspath(png_file),
|
||||
)
|
||||
resources.append(Resource('hint-point', hp))
|
||||
resources.append(Resource('hint-point', hp, definition.description or ''))
|
||||
else:
|
||||
raise ValueError(f'Unknown definition type: {definition.type}')
|
||||
|
||||
|
@ -250,7 +253,7 @@ def load_basic_sprite(root_path: str, png_file: str) -> Resource:
|
|||
abs_path=os.path.abspath(png_file),
|
||||
origin_file=os.path.abspath(png_file)
|
||||
)
|
||||
return Resource('template', spr)
|
||||
return Resource('template', spr, "")
|
||||
|
||||
def load_sprites(root_path: str, png_files: list[str]) -> list[Resource]:
|
||||
""""""
|
||||
|
@ -322,6 +325,7 @@ def make_classes(resources: list[Resource], output_path: str) -> list[OutputClas
|
|||
height = ''
|
||||
docstring = (
|
||||
f"名称:{sprite.display_name}\\n\n"
|
||||
f"描述:{resource.description}\\n\n"
|
||||
f"路径:{escape(sprite.rel_path)}\\n\n"
|
||||
f"模块:`{'.'.join(sprite.class_path)}`\\n\n"
|
||||
f'<img src="vscode-file://vscode-app/{escape(sprite.abs_path)}" title="{sprite.display_name}" />\\n\n'
|
||||
|
@ -353,6 +357,7 @@ def make_classes(resources: list[Resource], output_path: str) -> list[OutputClas
|
|||
|
||||
docstring = (
|
||||
f"名称:{hint_box.display_name}\\n\n"
|
||||
f"描述:{resource.description}\\n\n"
|
||||
f"模块:`{'.'.join(hint_box.class_path)}`\\n\n"
|
||||
f"值:x1={hint_box.x1}, y1={hint_box.y1}, x2={hint_box.x2}, y2={hint_box.y2}\\n\n"
|
||||
f"裁剪区域:\\n\n"
|
||||
|
@ -377,6 +382,7 @@ def make_classes(resources: list[Resource], output_path: str) -> list[OutputClas
|
|||
assert isinstance(hint_point, HintPoint)
|
||||
docstring = (
|
||||
f"名称:{hint_point.display_name}\\n\n"
|
||||
f"描述:{resource.description}\\n\n"
|
||||
f"模块:`{'.'.join(hint_point.class_path)}`\\n\n"
|
||||
f"坐标:(x={hint_point.x}, y={hint_point.y})\\n\n"
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue