Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@

### 추가

- 묶음(`doc.shapes.add_container`)에 선·글상자·그림·묶음 안 묶음 부재를 더한다: `ContainerMember.line`,
`ContainerMember.text_box`, `ContainerMember.picture`, `ContainerMember.group`.
- 선은 두 끝 중 왼쪽 위에 놓이고, 두 끝을 그 모서리 기준으로 지닌다.
- 글상자는 사각형에 `set_draw_text`와 같은 글을 담는다(이름·편집 가능·여백·글자 모양·문단 모양·세로 정렬).
글은 묶음이 구역에 들어간 뒤 쓰여 문단 id가 구역에서 겹치지 않는다. 잘못된 세로 정렬은 문서를 바꾸기 전에
거부한다.
- 그림은 `doc.media.add_image`가 돌려준 이진 항목을 받아 주어진 크기에 그린다. 이진 항목이 비면
`shape-container-picture-image`로 거부한다.
- 묶음 안 묶음은 꼬리(`sz`·`pos`·`outMargin`·`shapeComment`) 없는 부재다. 모든 깊이의 도형은 가장 바깥 묶음의
좌표에 놓인다. 한/글은 각 도형을 그 좌표의 자기 `transMatrix`에 그리므로, 안쪽 묶음 좌표에 둔 도형은 바깥
묶음의 왼쪽 위에 겹쳐 그려진다.
- 한/글이 저장한 묶음처럼 모든 부재는 `id`·`zOrder` 0, `numberingType="NONE"`이고, `groupLevel`은 깊이다
(1, 2, 3…).
- 묶음은 부재를 복사해 조립한다. 넘긴 `ContainerMember`는 바뀌지 않으므로 같은 부재를 여러 묶음이나 한 묶음에
다시 써도 된다.
- 표 구조 편집(`hwpx.table_patch.apply_table_ops`)에 열 삽입 `insert_column_by_clone`을 더한다. 격자 열
`ref_col`의 오른쪽(`side: "left"`면 왼쪽)에 그 열을 복제한 열 `count`개를 넣는다.
- 새 열은 기준 열과 같은 폭이고, 표는 그만큼 넓어진다. 본문 폭을 넘어도 줄이지 않는다.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ GitHub Release에 첨부되는 `py3-none-any` wheel을 문서와 함께 올리
- `add_shape()` / `add_control()`은 저수준 탈출구라, 그대로 저장하면 한/글이
열지 못하는 파일이 됩니다(호출 시 경고만 나옵니다). 도형은 `add_line()` /
`add_rectangle()` / `add_ellipse()`를 쓰세요.
- 그림은 단순 개체 생성까지 지원합니다 (그룹·효과 미지원).
- 그림은 단순 개체 생성과 묶음 안 그림까지 지원합니다 (효과 미지원).
- 암호화된 HWPX와 암호·배포용 HWP는 지원하지 않습니다.

## 기여하기
Expand Down
4 changes: 2 additions & 2 deletions README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ at all, and where uploads land, varies by plan and settings.
- `add_shape()` / `add_control()` are low-level escape hatches — a document
saved as-is will not open in Hancom, and the only signal is a warning at call
time. For shapes use `add_line()` / `add_rectangle()` / `add_ellipse()`.
- Pictures: simple picture objects can be generated; complex ones (groups,
effects) cannot.
- Pictures: simple picture objects and pictures inside groups can be generated;
effects cannot.
- Encrypted HWPX files and password-protected or distribution HWP files are not supported.

## Contributing
Expand Down
6 changes: 6 additions & 0 deletions docs/architecture/module-ownership.json
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,12 @@
"approvedBy": "hancom-merge-cells-grid",
"rationale": "What a cell merge leaves behind in a table's grid: collapse_merged_grid() removes the rows a merge left without cells and the columns no cell starts at, as Hancom's merge does (Hancom does not open a table with an empty hp:tr), and moves the cell addresses, spans and cell zones past them back. A new module rather than more table.py lines: with the merge fix that owner file would pass the 1,600-line cap; HwpxOxmlTable.merge_cells calls it. Format-level only."
},
{
"path": "src/hwpx/oxml/container.py",
"disposition": "core",
"approvedBy": "hancom-group-members",
"rationale": "Groups (hp:container) and their members: ContainerMember (rect, ellipse, polygon, line, text_box, picture, group) and the assembly of members into a group at any depth, as Hancom saves its groups (members without the sz/pos/outMargin/shapeComment tail, id and zOrder 0, numberingType NONE, groupLevel = depth, every shape placed in the outermost group's space). Moved out of objects.py with the new member kinds: that owner file would pass the 1,600-line cap; objects.py re-exports ContainerMember and _create_container_element and its paragraph add_container calls this module. Format-level only."
},
{
"path": "src/hwpx/oxml/table_structure.py",
"disposition": "core",
Expand Down
1 change: 1 addition & 0 deletions docs/error-codes.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ except HwpxError as exc:
| `shape-connector-side-invalid` | 연결선 끝의 변이 top/right/bottom/left 밖이다. |
| `shape-connector-target-inline` | 연결선을 이으려는 도형이 글자처럼 놓였거나 instid 가 없다. |
| `shape-container-no-members` | add_container 에 부재를 하나도 안 줬다. |
| `shape-container-picture-image` | 그룹의 그림 부재(ContainerMember.picture)에 그림 이진 항목을 안 줬다. |
| `shape-curve-too-few-points` | add_curve 에 앵커를 2개(닫으면 3개) 미만으로 줬다. |
| `shape-draw-text-vert-align` | 도형 글상자 vert_align 값이 OWPML 어휘(hp:subList/@vertAlign, TOP/CENTER/BOTTOM) 밖이다. |
| `shape-drop-cap-anchor-detached` | 만든 드롭캡이 요청한 dropcapstyle 을 안 갖고 있다(방어적 분기). |
Expand Down
4 changes: 2 additions & 2 deletions docs/python-example-ledger.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
"fenceCount": 115,
"sourceSha256": "b924d97f4a04691b26d3098514b1e2db25faac02715aa9646fedc91ca5182444",
"manualSha256": {
"README.md": "abce12159ada8d3d6006ff4fa695e78286db3ceb1bf382ff40974098f8e12dcc",
"README_EN.md": "efa11468f453229a5293105413e6e398f4e41f6c8b4f17af57b60ceb4090e627",
"README.md": "93d578be0712c8008cd8ad76456a8976ef0c7b448cf4539df63139464d4141bd",
"README_EN.md": "ea5e0819d85429278b85a5377de09fffafd9c27a9c9185a41a6c533ebaae0f95",
"docs/quickstart.md": "44d8ca82ee70c0e3dfdf087713a4e4ce935e64cd3f6a546311f95b054a285a18",
"docs/recipes-traversal.md": "b63f42b1a6ed23812688599474dcf83300509b86a94b5daceae679bfdbde9343",
"docs/mutation-semantics.md": "4a9f27d95c67d117d149ca73aefe02e8b7064d04a021c471f81581e3961c3e1d",
Expand Down
4 changes: 2 additions & 2 deletions docs/support-matrix.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/hwpx/_document/ns/shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,8 @@ def add_container(
section: "int | Section | None" = None,
section_index: int | None = None,
) -> "Shape":
"""도형을 그룹으로 묶는다(`ContainerMember.rect`/`.ellipse`/`.polygon`으로
각 부재를 그룹 로컬 좌표로 만들어 넘긴다)."""
"""도형을 그룹으로 묶는다(`ContainerMember.rect`/`.ellipse`/`.polygon`/`.line`/
`.text_box`/`.picture`/`.group`으로 각 부재를 그룹 로컬 좌표로 만들어 넘긴다)."""

from .. import shapes as _shapes

Expand Down
3 changes: 2 additions & 1 deletion src/hwpx/_document/shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,8 @@ def add_container(
"""Insert a group (``<hp:container>``) wrapping *members*.

Each member is built with :class:`hwpx.oxml.ContainerMember`'s
``rect``/``ellipse``/``polygon`` classmethods, which take the member's
``rect``/``ellipse``/``polygon``/``line``/``text_box``/``picture``/``group``
classmethods, which take the member's
position in the group's own local coordinate space (HWPUNIT, top-left
anchored) alongside its usual shape parameters::

Expand Down
Loading
Loading