diff --git a/.claude/skills/mxl-compile/SKILL.md b/.claude/skills/mxl-compile/SKILL.md
index 7e61a227..d0f9cb80 100644
--- a/.claude/skills/mxl-compile/SKILL.md
+++ b/.claude/skills/mxl-compile/SKILL.md
@@ -67,7 +67,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/mxl-compile.ps1" -J
header: { left, center, right, font, verticalAlignment, show, startPage }, footer: { … },
printSettings: { pageOrientation, topMargin, …, fitToPage, firstPageNumber },
columnSets: { name: { columns, columnWidths, columnStyles } },
- pictures: { name: { ref } | { data, transparent, transparentPixel } | {} },
+ pictures: { name: { ref } | { data } | {} + transparent: false | { x, y } },
drawings: [{ type, begin: { row, col, dy, dx }, end: { … }, picture, pictureSize,
text, name, detail, style, line, sides, id, zOrder }]
}
diff --git a/.claude/skills/mxl-compile/reference/dsl-spec.md b/.claude/skills/mxl-compile/reference/dsl-spec.md
index dab01931..442a43bc 100644
--- a/.claude/skills/mxl-compile/reference/dsl-spec.md
+++ b/.claude/skills/mxl-compile/reference/dsl-spec.md
@@ -386,7 +386,7 @@
```json
"pictures": {
"знак": { "ref": "v8ui:Стоп48" },
- "логотип": { "data": "iVBORw0KGgo...", "transparent": false }
+ "логотип": { "data": "iVBORw0KGgo...", "transparent": { "x": 24, "y": 29 } }
},
"drawings": [
{ "type": "Picture", "picture": "логотип", "name": "Логотип",
@@ -422,10 +422,9 @@
Запись в `pictures` — либо ссылка (`ref`), либо сами данные в base64 (`data`). Ссылкой
задаются и предопределённая картинка платформы, и общая картинка конфигурации — пишутся они
одинаково, префиксом `v8ui:`. Пустая запись `{}` — картинка не задана, такое в макетах встречается.
-С данными сочетаются `transparent` и `transparentPixel` — два способа записать прозрачность,
-исключающие друг друга: `transparent: false` — прозрачного фона нет,
-`transparentPixel: { "x": …, "y": … }` — прозрачным считается цвет пикселя с этими координатами
-(Конфигуратор по флажку «прозрачный фон» берёт правый нижний пиксель картинки).
+Прозрачность задаётся ключом `transparent` в одной из двух форм: `false` — прозрачного фона
+нет; `{ "x": …, "y": … }` — прозрачным считается цвет пикселя с этими координатами внутри
+картинки (по флажку «прозрачный фон» Конфигуратор берёт её правый нижний пиксель).
Одну запись `pictures` могут использовать несколько рисунков — данные в макете не дублируются.
diff --git a/.claude/skills/mxl-compile/scripts/mxl-compile.ps1 b/.claude/skills/mxl-compile/scripts/mxl-compile.ps1
index 5d19937b..8f3d45b5 100644
--- a/.claude/skills/mxl-compile/scripts/mxl-compile.ps1
+++ b/.claude/skills/mxl-compile/scripts/mxl-compile.ps1
@@ -1,4 +1,4 @@
-# mxl-compile v1.49 — Compile 1C spreadsheet from JSON
+# mxl-compile v1.50 — Compile 1C spreadsheet from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -1307,7 +1307,7 @@ function Set-CellProp {
function Test-CellObject {
param($el)
$cellKeys = @('col', 'span', 'rowspan', 'style', 'param', 'detail', 'text', 'template',
- 'valueType', 'controlType', 'value', 'control', 'note')
+ 'valueType', 'controlType', 'value', 'control', 'note', 'pictureParameter')
foreach ($p in $el.PSObject.Properties) {
if ($cellKeys -contains $p.Name) { return $true }
}
@@ -1603,16 +1603,23 @@ if ($def.pictures) {
$entry = @{ Ref = ''; Data = ''; Transparent = ''; PixelX = ''; PixelY = '' }
if ($pr.Value.ref) { $entry.Ref = "$($pr.Value.ref)" }
if ($null -ne $pr.Value.data) { $entry.Data = "$($pr.Value.data)" }
- if ($null -ne $pr.Value.transparent) {
- $entry.Transparent = if ($pr.Value.transparent -eq $true -or "$($pr.Value.transparent)" -eq 'true') { 'true' } else { 'false' }
+ # Прозрачность — одна сущность диалога, записанная двумя способами: выключенную
+ # платформа хранит атрибутом, включённую — координатами пикселя, чей цвет прозрачен.
+ # Поэтому и ключ один, а форма значения выбирает способ.
+ $tr = $pr.Value.transparent
+ if ($null -ne $tr) {
+ if ($tr -is [bool] -or "$tr" -ceq 'true' -or "$tr" -ceq 'false') {
+ $entry.Transparent = if ($tr -eq $true -or "$tr" -ceq 'true') { 'true' } else { 'false' }
+ } elseif ($null -ne $tr.x -and $null -ne $tr.y) {
+ $entry.PixelX = "$([int]$tr.x)"
+ $entry.PixelY = "$([int]$tr.y)"
+ } else {
+ [Console]::Error.WriteLine("pictures[$($pr.Name)]: 'transparent' is either false/true or { x, y }")
+ exit 1
+ }
}
- if ($null -ne $pr.Value.transparentPixel) {
- $entry.PixelX = "$([int]$pr.Value.transparentPixel.x)"
- $entry.PixelY = "$([int]$pr.Value.transparentPixel.y)"
- }
- if (-not $entry.Ref -and -not $entry.Data -and
- ($entry.Transparent -or $entry.PixelX)) {
- [Console]::Error.WriteLine("pictures[$($pr.Name)]: 'transparent' and 'transparentPixel' require 'ref' or 'data'")
+ if (-not $entry.Ref -and -not $entry.Data -and ($entry.Transparent -or $entry.PixelX)) {
+ [Console]::Error.WriteLine("pictures[$($pr.Name)]: 'transparent' requires 'ref' or 'data'")
exit 1
}
$pictureEntries += $entry
@@ -1976,8 +1983,9 @@ foreach ($area in $def.areas) {
$cellInfo = @{
Col = $colStart - 1 # 0-based
FormatIdx = $fmtIdx
- Param = $cell.param
- Detail = $cell.detail
+ Param = $cell.param
+ Detail = $cell.detail
+ PictureParam = $cell.pictureParameter
Text = $cell.text
Template = $cell.template
Value = $(if ($vp.Count -gt 0) { Get-CellValue $cell "$($vp['valueType'])" "area `"$areaName`", row $($localRow + 1)" } else { $null })
@@ -2118,6 +2126,13 @@ foreach ($area in $def.areas) {
X "`t`t`t`t`t$($cellInfo.Detail)"
}
+ # Третий параметр ячейки — имя параметра, которым подставляют картинку. Сама
+ # картинка при этом задаётся оформлением (picIndex), а параметр — тут, последним
+ # из параметров ячейки (21 ячейка корпуса, порядок везде такой).
+ if ($cellInfo.PictureParam) {
+ X "`t`t`t`t`t$(Esc-XmlText $cellInfo.PictureParam)"
+ }
+
# Якорь конца примечания — координаты самой ячейки, поэтому его не задают:
# он выводится здесь, при эмиссии.
if ($null -ne $cellInfo.Note) {
diff --git a/.claude/skills/mxl-compile/scripts/mxl-compile.py b/.claude/skills/mxl-compile/scripts/mxl-compile.py
index 8f0b8973..6d3ec4a4 100644
--- a/.claude/skills/mxl-compile/scripts/mxl-compile.py
+++ b/.claude/skills/mxl-compile/scripts/mxl-compile.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# mxl-compile v1.49 — Compile 1C spreadsheet from JSON
+# mxl-compile v1.50 — Compile 1C spreadsheet from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import hashlib
@@ -1299,7 +1299,7 @@ def main():
ключей есть ключ схемы ячейки, во втором ключи — идентификаторы языков. Пересечений
нет: в корпусе это ru, en, ru1, Русский."""
cell_keys = ('col', 'span', 'rowspan', 'style', 'param', 'detail', 'text', 'template',
- 'valueType', 'controlType', 'value', 'control')
+ 'valueType', 'controlType', 'value', 'control', 'note', 'pictureParameter')
return any(k in el for k in cell_keys)
def expand_shorthand_row(row, area_name, row_idx, open_by_col, max_cols):
@@ -1560,14 +1560,21 @@ def main():
entry['Ref'] = str(pic_def['ref'])
if pic_def.get('data') is not None:
entry['Data'] = str(pic_def['data'])
- if pic_def.get('transparent') is not None:
- entry['Transparent'] = 'true' if (pic_def['transparent'] is True
- or str(pic_def['transparent']).lower() == 'true') else 'false'
- if pic_def.get('transparentPixel') is not None:
- entry['PixelX'] = str(int(pic_def['transparentPixel'].get('x', 0)))
- entry['PixelY'] = str(int(pic_def['transparentPixel'].get('y', 0)))
+ # Прозрачность — одна сущность диалога, записанная двумя способами: выключенную
+ # платформа хранит атрибутом, включённую — координатами пикселя, чей цвет прозрачен.
+ # Поэтому и ключ один, а форма значения выбирает способ.
+ tr = pic_def.get('transparent')
+ if tr is not None:
+ if isinstance(tr, bool) or str(tr).lower() in ('true', 'false'):
+ entry['Transparent'] = 'true' if (tr is True or str(tr).lower() == 'true') else 'false'
+ elif isinstance(tr, dict) and 'x' in tr and 'y' in tr:
+ entry['PixelX'] = str(int(tr['x']))
+ entry['PixelY'] = str(int(tr['y']))
+ else:
+ print(f"pictures[{pic_name}]: 'transparent' is either false/true or {{ x, y }}", file=sys.stderr)
+ sys.exit(1)
if not entry['Ref'] and not entry['Data'] and (entry['Transparent'] or entry['PixelX']):
- print(f"pictures[{pic_name}]: 'transparent' and 'transparentPixel' require 'ref' or 'data'", file=sys.stderr)
+ print(f"pictures[{pic_name}]: 'transparent' requires 'ref' or 'data'", file=sys.stderr)
sys.exit(1)
picture_entries.append(entry)
picture_names[pic_name] = len(picture_entries)
@@ -1885,6 +1892,7 @@ def main():
'FormatIdx': fmt_idx,
'Param': cell.get('param'),
'Detail': cell.get('detail'),
+ 'PictureParam': cell.get('pictureParameter'),
'Text': cell.get('text'),
'Template': cell.get('template'),
'Value': (cell_value(cell, vp.get('valueType', ''),
@@ -2015,6 +2023,13 @@ def main():
if cell_info['Detail']:
lines.append(f'\t\t\t\t\t{cell_info["Detail"]}')
+ # Третий параметр ячейки — имя параметра, которым подставляют картинку. Сама
+ # картинка при этом задаётся оформлением (picIndex), а параметр — тут, последним
+ # из параметров ячейки (21 ячейка корпуса, порядок везде такой).
+ if cell_info.get('PictureParam'):
+ lines.append('\t\t\t\t\t'
+ f'{esc_xml_text(cell_info["PictureParam"])}')
+
# Якорь конца примечания — координаты самой ячейки, поэтому его не задают:
# он выводится здесь, при эмиссии.
if cell_info.get('Note') is not None:
diff --git a/.claude/skills/mxl-decompile/scripts/mxl-decompile.ps1 b/.claude/skills/mxl-decompile/scripts/mxl-decompile.ps1
index f67f4e70..9775c3f6 100644
--- a/.claude/skills/mxl-decompile/scripts/mxl-decompile.ps1
+++ b/.claude/skills/mxl-decompile/scripts/mxl-decompile.ps1
@@ -1,4 +1,4 @@
-# mxl-decompile v1.28 — Decompile 1C spreadsheet to JSON
+# mxl-decompile v1.29 — Decompile 1C spreadsheet to JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -290,7 +290,7 @@ foreach ($picNode in $root.SelectNodes("d:picture", $ns)) {
$entry["transparent"] = ($inner.GetAttribute('t') -ceq 'true')
}
if ($entry.Count -gt 0 -and $inner.HasAttribute('tx')) {
- $entry["transparentPixel"] = [ordered]@{
+ $entry["transparent"] = [ordered]@{
x = [int]$inner.GetAttribute('tx')
y = [int]$inner.GetAttribute('ty')
}
@@ -603,6 +603,12 @@ foreach ($riNode in $root.SelectNodes("d:rowsItem", $ns)) {
$dNode = $cContent.SelectSingleNode("d:detailParameter", $ns)
if ($dNode) { $detail = $dNode.InnerText }
+ # Имя параметра, которым подставляют картинку. Сама картинка сидит в
+ # оформлении (picIndex), поэтому этот тег живёт отдельно от неё.
+ $picParam = $null
+ $ppNode = $cContent.SelectSingleNode("d:pictureParameter", $ns)
+ if ($ppNode) { $picParam = $ppNode.InnerText }
+
# Значение ячейки-поля ввода. Тип значения свой, из объявленного не выводится,
# поэтому читаем и его.
$value = $null
@@ -685,6 +691,7 @@ foreach ($riNode in $root.SelectNodes("d:rowsItem", $ns)) {
FormatIdx = $cellFmtIdx
Param = $param
Detail = $detail
+ PictureParam = $picParam
Value = $value
Control = $control
Note = $note
@@ -1337,7 +1344,7 @@ foreach ($area in $blocks) {
$hasValue = ($cf -and $cf.Props['containsValue'] -ceq 'true')
# Расшифровка сама по себе делает ячейку содержательной: в корпусе 12 653 ячейки
# несут только её. Без этого такая ячейка уходила в заполнители и терялась.
- $hasContent = $cell.Param -or $cell.HasText -or $hasValue -or $cell.Detail -or $cell.Note
+ $hasContent = $cell.Param -or $cell.HasText -or $hasValue -or $cell.Detail -or $cell.Note -or $cell.PictureParam
$hasMerge = $mergeMap.ContainsKey("$globalRow,$($cell.Col)")
if ($hasContent -or $hasMerge) {
@@ -1455,6 +1462,7 @@ foreach ($area in $blocks) {
# несут её без параметра против 8 582 с ним. Пока она читалась только вместе
# с параметром, две трети расшифровок терялись молча.
if ($cell.Detail) { $dslCell["detail"] = $cell.Detail }
+ if ($cell.PictureParam) { $dslCell["pictureParameter"] = $cell.PictureParam }
if ($cell.Note) {
$n = $cell.Note
diff --git a/.claude/skills/mxl-decompile/scripts/mxl-decompile.py b/.claude/skills/mxl-decompile/scripts/mxl-decompile.py
index ad680ba4..c9819005 100644
--- a/.claude/skills/mxl-decompile/scripts/mxl-decompile.py
+++ b/.claude/skills/mxl-decompile/scripts/mxl-decompile.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
-# mxl-decompile v1.28 — Decompile 1C spreadsheet to JSON
+# mxl-decompile v1.29 — Decompile 1C spreadsheet to JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -451,8 +451,8 @@ def main():
if entry and inner.get("t") is not None:
entry["transparent"] = inner.get("t") == "true"
if entry and inner.get("tx") is not None:
- entry["transparentPixel"] = OrderedDict([("x", int(inner.get("tx"))),
- ("y", int(inner.get("ty") or 0))])
+ entry["transparent"] = OrderedDict([("x", int(inner.get("tx"))),
+ ("y", int(inner.get("ty") or 0))])
pictures_out[name] = entry
picture_key[pic_i] = name
@@ -738,6 +738,13 @@ def main():
if d_node is not None and d_node.text:
detail = d_node.text
+ # Имя параметра, которым подставляют картинку. Сама картинка сидит в
+ # оформлении (picIndex), поэтому этот тег живёт отдельно от неё.
+ pic_param = None
+ pp_node = find(c_content, "d:pictureParameter")
+ if pp_node is not None and pp_node.text:
+ pic_param = pp_node.text
+
# Значение ячейки-поля ввода. Тип значения свой, из объявленного не выводится,
# поэтому читаем и его: пустое значение сворачивается в "", остальные едут как есть.
value = None
@@ -814,6 +821,7 @@ def main():
"FormatIdx": cell_fmt_idx,
"Param": param,
"Detail": detail,
+ "PictureParam": pic_param,
"Value": value,
"Control": control,
"Note": note,
@@ -1296,7 +1304,7 @@ def main():
# Расшифровка сама по себе делает ячейку содержательной: в корпусе 12 653 ячейки
# несут только её. Без этого такая ячейка уходила в заполнители и терялась.
has_content = (cell["Param"] or cell["HasText"] or has_value
- or cell["Detail"] or cell["Note"])
+ or cell["Detail"] or cell["Note"] or cell["PictureParam"])
has_merge = f"{global_row},{cell['Col']}" in merge_map
if has_content or has_merge:
@@ -1409,6 +1417,8 @@ def main():
# с параметром, две трети расшифровок терялись молча.
if cell["Detail"]:
dsl_cell["detail"] = cell["Detail"]
+ if cell["PictureParam"]:
+ dsl_cell["pictureParameter"] = cell["PictureParam"]
if cell["Note"]:
n = cell["Note"]
diff --git a/docs/mxl-dsl-spec.md b/docs/mxl-dsl-spec.md
index 4a4aeb11..f1738cee 100644
--- a/docs/mxl-dsl-spec.md
+++ b/docs/mxl-dsl-spec.md
@@ -394,7 +394,7 @@
```json
"pictures": {
"знак": { "ref": "v8ui:Стоп48" },
- "логотип": { "data": "iVBORw0KGgo...", "transparent": false }
+ "логотип": { "data": "iVBORw0KGgo...", "transparent": { "x": 24, "y": 29 } }
},
"drawings": [
{ "type": "Picture", "picture": "логотип", "name": "Логотип",
@@ -430,10 +430,9 @@
Запись в `pictures` — либо ссылка (`ref`), либо сами данные в base64 (`data`). Ссылкой
задаются и предопределённая картинка платформы, и общая картинка конфигурации — пишутся они
одинаково, префиксом `v8ui:`. Пустая запись `{}` — картинка не задана, такое в макетах встречается.
-С данными сочетаются `transparent` и `transparentPixel` — два способа записать прозрачность,
-исключающие друг друга: `transparent: false` — прозрачного фона нет,
-`transparentPixel: { "x": …, "y": … }` — прозрачным считается цвет пикселя с этими координатами
-(Конфигуратор по флажку «прозрачный фон» берёт правый нижний пиксель картинки).
+Прозрачность задаётся ключом `transparent` в одной из двух форм: `false` — прозрачного фона
+нет; `{ "x": …, "y": … }` — прозрачным считается цвет пикселя с этими координатами внутри
+картинки (по флажку «прозрачный фон» Конфигуратор берёт её правый нижний пиксель).
Одну запись `pictures` могут использовать несколько рисунков — данные в макете не дублируются.
diff --git a/tests/skills/cases/mxl-compile/cell-picture-parameter.json b/tests/skills/cases/mxl-compile/cell-picture-parameter.json
new file mode 100644
index 00000000..d71e921b
--- /dev/null
+++ b/tests/skills/cases/mxl-compile/cell-picture-parameter.json
@@ -0,0 +1,19 @@
+{
+ "name": "Картинка в ячейке, подставляемая параметром",
+ "input": {
+ "columns": 3,
+ "pictures": { "статус": { "ref": "v8ui:Стоп48" } },
+ "styles": {
+ "значок": { "picIndex": 1, "picHorizontalAlignment": "Center", "picVerticalAlignment": "Center", "textPosition": "Bottom" }
+ },
+ "areas": [{
+ "rows": [
+ { "cells": [
+ { "col": 1, "style": "значок", "text": "удалить", "pictureParameter": "Удалить" },
+ { "col": 2, "param": "ПорядковыйНомер", "detail": "Строка", "pictureParameter": "Пиктограмма" }
+ ]}
+ ]
+ }]
+ },
+ "params": { "outputPath": "Template.xml" }
+}
diff --git a/tests/skills/cases/mxl-compile/error-picture-transparent-without-data.json b/tests/skills/cases/mxl-compile/error-picture-transparent-without-data.json
index b3524da5..a66ffe7b 100644
--- a/tests/skills/cases/mxl-compile/error-picture-transparent-without-data.json
+++ b/tests/skills/cases/mxl-compile/error-picture-transparent-without-data.json
@@ -6,5 +6,5 @@
"areas": [{ "rows": [["Бланк"]] }]
},
"params": { "outputPath": "Template.xml" },
- "expectError": "pictures[пусто]: 'transparent' and 'transparentPixel' require 'ref' or 'data'"
+ "expectError": "pictures[пусто]: 'transparent' requires 'ref' or 'data'"
}
diff --git a/tests/skills/cases/mxl-compile/pictures-empty-and-transparent.json b/tests/skills/cases/mxl-compile/pictures-empty-and-transparent.json
index b5c9a387..d734354d 100644
--- a/tests/skills/cases/mxl-compile/pictures-empty-and-transparent.json
+++ b/tests/skills/cases/mxl-compile/pictures-empty-and-transparent.json
@@ -7,7 +7,7 @@
"значок": { "ref": "v8ui:Стоп48", "transparent": false },
"точка": {
"data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/q842iQAAAABJRU5ErkJggg==",
- "transparentPixel": { "x": 3, "y": 5 }
+ "transparent": { "x": 3, "y": 5 }
}
},
"areas": [{ "rows": [["Бланк"]] }],
diff --git a/tests/skills/cases/mxl-compile/snapshots/cell-picture-parameter/Template.xml b/tests/skills/cases/mxl-compile/snapshots/cell-picture-parameter/Template.xml
new file mode 100644
index 00000000..0ec34cd5
--- /dev/null
+++ b/tests/skills/cases/mxl-compile/snapshots/cell-picture-parameter/Template.xml
@@ -0,0 +1,60 @@
+
+
+
+ ru
+ ru
+
+ ru
+ Русский
+ Русский
+
+
+
+ 3
+
+
+ 0
+
+
+
+ 1
+
+
+ ru
+ удалить
+
+
+ Удалить
+
+
+
+
+ 2
+ ПорядковыйНомер
+ Строка
+ Пиктограмма
+
+
+
+
+ true
+ 3
+ 1
+ 1
+
+ 1
+ Center
+ Center
+ Bottom
+
+
+ Parameter
+
+
+ 10
+
+
+ 0
+
+
+
\ No newline at end of file