mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-08-23 03:18:15 +00:00
fix(composer): point the align toolbar at the anchor-clearing path
Two alignment implementations existed and the toolbar used the wrong one. alignElement(dir) set el.x/el.y and stopped there. resolveAnchor turns anchor='right' into `dim - val`, so with xAnchor='right' an "align left" (el.x = 0) resolved to x = MATRIX_W and the element jumped to the far right edge -- the opposite of what was asked. It also never touched el.x0/el.y0, so a line's endpoints were left where they were. _alignElement already did both correctly: it clears the anchor so the stored value is absolute, and moves x0/y0 for lines. Its six wrappers -- alignLeft, alignHCenter, alignRight, alignTop, alignVCenter, alignBottom -- existed and had no callers at all. All six toolbar buttons now call the wrappers, and the legacy method is removed rather than left to drift back into use. Tests: the toolbar calls each wrapper and no longer calls alignElement, the legacy definition is gone, and _alignElement still clears the anchor and moves line endpoints. Two of them fail against the previous markup. Full suite 4062 passed, the one failure being test_install_lowmem (pre-existing, awaiting #492). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STMbQE4YctTacQXfbYqKuW
This commit is contained in:
co-authored by
Claude Opus 5
parent
37fc1b56b5
commit
2f42d179f6
@@ -145,3 +145,43 @@ def test_restore_path_stays_snapshot_free(method):
|
|||||||
snap = body.index("_snapshot()")
|
snap = body.index("_snapshot()")
|
||||||
guard = body.index("!opts.silent")
|
guard = body.index("!opts.silent")
|
||||||
assert guard < snap, f"{method} snapshots outside the !opts.silent guard"
|
assert guard < snap, f"{method} snapshots outside the !opts.silent guard"
|
||||||
|
|
||||||
|
|
||||||
|
TEMPLATE_HTML = (Path(__file__).resolve().parent.parent
|
||||||
|
/ "web_interface/templates/v3/composer.html")
|
||||||
|
|
||||||
|
#: The six toolbar buttons and the wrapper each must call.
|
||||||
|
ALIGN_BUTTONS = ["alignLeft", "alignHCenter", "alignRight",
|
||||||
|
"alignTop", "alignVCenter", "alignBottom"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_alignment_buttons_use_the_anchor_clearing_path():
|
||||||
|
"""Two alignment implementations existed and the toolbar used the wrong one.
|
||||||
|
|
||||||
|
The legacy alignElement(dir) set el.x/el.y but left xAnchor/yAnchor in
|
||||||
|
place. resolveAnchor turns anchor='right' into `dim - val`, so "align left"
|
||||||
|
(el.x = 0) resolved to x = MATRIX_W -- the element jumped to the far right
|
||||||
|
edge instead. _alignElement clears the anchor first, so the stored value is
|
||||||
|
absolute, and it also updates el.x0/el.y0 so lines actually move.
|
||||||
|
"""
|
||||||
|
html = TEMPLATE_HTML.read_text()
|
||||||
|
for wrapper in ALIGN_BUTTONS:
|
||||||
|
assert f"{wrapper}()" in html, f"toolbar does not call {wrapper}()"
|
||||||
|
assert not re.search(r"[^_]alignElement\(", html), \
|
||||||
|
"toolbar still calls the legacy alignElement()"
|
||||||
|
|
||||||
|
|
||||||
|
def test_the_legacy_alignelement_is_gone():
|
||||||
|
"""Leaving it in place invites the toolbar drifting back to it."""
|
||||||
|
src = APP.read_text()
|
||||||
|
assert not re.search(r"^\s{4}alignElement\(dir\)", src, re.M), \
|
||||||
|
"legacy alignElement(dir) still defined"
|
||||||
|
|
||||||
|
|
||||||
|
def test_align_clears_the_anchor_and_moves_line_endpoints():
|
||||||
|
body = _method_source(APP, "_alignElement")
|
||||||
|
assert "xAnchor = null" in body and "yAnchor = null" in body, \
|
||||||
|
"_alignElement no longer clears the anchor, so aligning an anchored " \
|
||||||
|
"element resolves to the wrong edge"
|
||||||
|
assert "el.x0" in body and "el.y0" in body, \
|
||||||
|
"_alignElement no longer moves line endpoints"
|
||||||
|
|||||||
@@ -1098,23 +1098,6 @@ function composerApp() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// ── Alignment ─────────────────────────────────────────────────────
|
// ── Alignment ─────────────────────────────────────────────────────
|
||||||
alignElement(dir) {
|
|
||||||
const el = this.selectedElement;
|
|
||||||
if (!el) return;
|
|
||||||
const bb = window.ComposerCanvas.getBoundingBox(el, this.MATRIX_W, this.MATRIX_H);
|
|
||||||
switch (dir) {
|
|
||||||
case 'left': el.x = 0; break;
|
|
||||||
case 'center': el.x = Math.round((this.MATRIX_W - bb.w) / 2); break;
|
|
||||||
case 'right': el.x = this.MATRIX_W - bb.w; break;
|
|
||||||
case 'top': el.y = 0; break;
|
|
||||||
case 'middle': el.y = Math.round((this.MATRIX_H - bb.h) / 2); break;
|
|
||||||
case 'bottom': el.y = this.MATRIX_H - bb.h; break;
|
|
||||||
}
|
|
||||||
this.isDirty = true;
|
|
||||||
this._snapshot();
|
|
||||||
this.render();
|
|
||||||
},
|
|
||||||
|
|
||||||
// ── Templates ─────────────────────────────────────────────────────
|
// ── Templates ─────────────────────────────────────────────────────
|
||||||
loadTemplate(tmpl) {
|
loadTemplate(tmpl) {
|
||||||
if (this.isDirty && this.elements.length > 0) {
|
if (this.isDirty && this.elements.length > 0) {
|
||||||
|
|||||||
@@ -667,13 +667,13 @@
|
|||||||
<div>
|
<div>
|
||||||
<span class="prop-label">Align to Canvas</span>
|
<span class="prop-label">Align to Canvas</span>
|
||||||
<div class="flex gap-0.5 mt-0.5 flex-wrap">
|
<div class="flex gap-0.5 mt-0.5 flex-wrap">
|
||||||
<button class="align-btn" @click="alignElement('left')" title="Align left"> <i class="fas fa-align-left"></i></button>
|
<button class="align-btn" @click="alignLeft()" title="Align left"> <i class="fas fa-align-left"></i></button>
|
||||||
<button class="align-btn" @click="alignElement('center')" title="Center horiz"><i class="fas fa-align-center"></i></button>
|
<button class="align-btn" @click="alignHCenter()" title="Center horiz"><i class="fas fa-align-center"></i></button>
|
||||||
<button class="align-btn" @click="alignElement('right')" title="Align right"> <i class="fas fa-align-right"></i></button>
|
<button class="align-btn" @click="alignRight()" title="Align right"> <i class="fas fa-align-right"></i></button>
|
||||||
<div class="w-px h-5 bg-gray-200 mx-0.5"></div>
|
<div class="w-px h-5 bg-gray-200 mx-0.5"></div>
|
||||||
<button class="align-btn" @click="alignElement('top')" title="Align top"> <i class="fas fa-arrow-up"></i></button>
|
<button class="align-btn" @click="alignTop()" title="Align top"> <i class="fas fa-arrow-up"></i></button>
|
||||||
<button class="align-btn" @click="alignElement('middle')" title="Center vert"> <i class="fas fa-arrows-alt-v"></i></button>
|
<button class="align-btn" @click="alignVCenter()" title="Center vert"> <i class="fas fa-arrows-alt-v"></i></button>
|
||||||
<button class="align-btn" @click="alignElement('bottom')" title="Align bottom"><i class="fas fa-arrow-down"></i></button>
|
<button class="align-btn" @click="alignBottom()" title="Align bottom"><i class="fas fa-arrow-down"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user