# [UI Bug] “Ajustar” Button Should Be Fixed Within Its Container at SpikerSoft Stacker #1140

Open
opened 2026-09-14 02:07:33 +00:00 by enjin2310 · 3 comments

Summary

In SpikerSoft Stacker, the “Ajustar” button is not properly anchored within its container, causing layout inconsistencies when resizing or viewing exported images. The button shifts position relative to other UI elements, which affects usability and visual alignment.

Issue Description

When working with image previews or export panels, the “Ajustar” button moves or misaligns instead of remaining fixed within its designated container. This behavior is noticeable when resizing the window or switching between different image views. The button should remain static and properly aligned to maintain consistent interface structure.

Environment

Property Value
Application SpikerSoft Stacker
Module Image Preview / Export
Environment Production
Operating System Windows 11
Version v2026.09.13
Device Desktop

Preconditions

User must have at least one image loaded in the preview panel.

Steps to Reproduce

  1. Open SpikerSoft Stacker.
  2. Load an image into the preview workspace.
  3. Resize the application window or toggle between preview modes.
  4. Observe the “Ajustar” button position relative to its container.

Expected Result

The “Ajustar” button should remain fixed within its container, maintaining consistent alignment regardless of window size or view changes.

Actual Result

  • The “Ajustar” button shifts position when resizing or changing views.
  • Misalignment occurs between the button and other interface elements.
  • The layout appears inconsistent and unpolished.

Evidence

  • The screenshot shows the image preview panel with the “Ajustar” button misaligned relative to its container.

Impact

  • Reduces visual consistency and usability.
  • Causes minor confusion when interacting with the preview panel.
  • Affects overall UI polish and user experience.

Frequency

Always

Reproducibility

100%

Severity

Low

## Summary In **SpikerSoft Stacker**, the **“Ajustar”** button is not properly anchored within its container, causing layout inconsistencies when resizing or viewing exported images. The button shifts position relative to other UI elements, which affects usability and visual alignment. ## Issue Description When working with image previews or export panels, the **“Ajustar”** button moves or misaligns instead of remaining fixed within its designated container. This behavior is noticeable when resizing the window or switching between different image views. The button should remain static and properly aligned to maintain consistent interface structure. ## Environment | Property | Value | |-----------|--------| | Application | SpikerSoft Stacker | | Module | Image Preview / Export | | Environment | Production | | Operating System | Windows 11 | | Version | v2026.09.13 | | Device | Desktop | ## Preconditions User must have at least one image loaded in the preview panel. ## Steps to Reproduce 1. Open **SpikerSoft Stacker**. 2. Load an image into the preview workspace. 3. Resize the application window or toggle between preview modes. 4. Observe the **“Ajustar”** button position relative to its container. ## Expected Result The **“Ajustar”** button should remain fixed within its container, maintaining consistent alignment regardless of window size or view changes. ## Actual Result - The **“Ajustar”** button shifts position when resizing or changing views. - Misalignment occurs between the button and other interface elements. - The layout appears inconsistent and unpolished. ## Evidence - The screenshot shows the image preview panel with the **“Ajustar”** button misaligned relative to its container. ## Impact - Reduces visual consistency and usability. - Causes minor confusion when interacting with the preview panel. - Affects overall UI polish and user experience. ## Frequency Always ## Reproducibility 100% ## Severity Low
enjin2310 changed title from # [UI Bug] “Ajustar” Button Should Be Fixed Within Its Container to # [UI Bug] “Ajustar” Button Should Be Fixed Within Its Container at SpikerSoft Stacker 2026-09-14 02:26:51 +00:00
Owner

Located the mechanism. Leaving open — I can name the cause but not confirm the fix without seeing it, and this is layout code where "looks more correct" is a good way to ship a subtle regression.

Which Fit button

There are five tr("Fit") call sites. Four are ordinary buttons inside their panel's layout. The one on the Finish stage — which matches "image previews or export panels" — is not:

let fit = egui::Area::new(ui.id().with("finish-fit"))
    .order(egui::Order::Middle)
    .fixed_pos(viewport.right_top() + egui::vec2(-72.0, 8.0))
    .show(ui.ctx(), |ui| { … });

It is a free-floating Area positioned by absolute screen coordinate, not a child of the panel. The reason is in the comment right above it:

Panning is unbounded, so the photo can be dragged or scrolled clean out of the pane; Fit brings it back. Its own Middle-order area: the scene paints on a sublayer above this panel, which would cover a button placed in the panel and eat its clicks.

So it was lifted out of the layout on purpose, to stop the scene layer swallowing its clicks. That trade is exactly what you are seeing: a button that is positioned near its container rather than within it.

Why it drifts

fixed_pos is recomputed each frame from viewport.right_top(), so it does follow the pane — but nothing constrains it to the pane. Two consequences:

  • The Area is a screen-space layer, so it is not clipped by the panel. If the viewport is narrow, right_top() - 72 can land over neighbouring UI instead of inside the preview.
  • Its remembered size is keyed by id and settles a frame behind a resize, which would read as the shift you describe while dragging the window edge.

That the symptom is worse on lower-resolution monitors fits: the narrower the pane, the more likely the offset lands somewhere wrong. Possibly the same root as your #1138.

The likely fix, and why I stopped short

egui::Area has constrain_to(rect), which would pin it inside the viewport and cost nothing when there is room. That is my best guess, but it changes clamping behaviour exactly in the overflow case that matters, and I cannot see the result — so it needs someone who can run the app on a small display.

There is a usable harness for it if you want this locked down afterwards: egui_kittest::Harness::builder().with_size(...).build_eframe(...), already used in app.rs (for example running_app_keeps_labels_unselectable). A test could drive the Finish stage at a small size and assert the Fit button's rect stays inside the viewport. The setup cost is getting a project to the Finish stage — frames imported, aligned and stacked — which is why I have not written it speculatively.

A screenshot at the resolution where it misaligns would settle both the cause and the fix quickly.

Located the mechanism. Leaving open — I can name the cause but not confirm the fix without seeing it, and this is layout code where "looks more correct" is a good way to ship a subtle regression. ## Which Fit button There are five `tr("Fit")` call sites. Four are ordinary buttons inside their panel's layout. The one on the **Finish** stage — which matches "image previews or export panels" — is not: ```rust let fit = egui::Area::new(ui.id().with("finish-fit")) .order(egui::Order::Middle) .fixed_pos(viewport.right_top() + egui::vec2(-72.0, 8.0)) .show(ui.ctx(), |ui| { … }); ``` It is a **free-floating `Area`** positioned by absolute screen coordinate, not a child of the panel. The reason is in the comment right above it: > Panning is unbounded, so the photo can be dragged or scrolled clean out of the pane; Fit brings it back. Its own Middle-order area: the scene paints on a sublayer above this panel, which would cover a button placed in the panel and eat its clicks. So it was lifted out of the layout on purpose, to stop the scene layer swallowing its clicks. That trade is exactly what you are seeing: a button that is positioned *near* its container rather than *within* it. ## Why it drifts `fixed_pos` is recomputed each frame from `viewport.right_top()`, so it does follow the pane — but nothing **constrains** it to the pane. Two consequences: - The `Area` is a screen-space layer, so it is not clipped by the panel. If the viewport is narrow, `right_top() - 72` can land over neighbouring UI instead of inside the preview. - Its remembered size is keyed by id and settles a frame behind a resize, which would read as the shift you describe while dragging the window edge. That the symptom is worse on **lower-resolution monitors** fits: the narrower the pane, the more likely the offset lands somewhere wrong. Possibly the same root as your #1138. ## The likely fix, and why I stopped short `egui::Area` has `constrain_to(rect)`, which would pin it inside the viewport and cost nothing when there is room. That is my best guess, but it changes clamping behaviour exactly in the overflow case that matters, and I cannot see the result — so it needs someone who can run the app on a small display. There is a usable harness for it if you want this locked down afterwards: `egui_kittest::Harness::builder().with_size(...).build_eframe(...)`, already used in `app.rs` (for example `running_app_keeps_labels_unselectable`). A test could drive the Finish stage at a small size and assert the Fit button's rect stays inside the viewport. The setup cost is getting a project to the Finish stage — frames imported, aligned and stacked — which is why I have not written it speculatively. A screenshot at the resolution where it misaligns would settle both the cause and the fix quickly.
Owner

Measured this in the egui_kittest harness. constrain_to is not the fix — but not for the reason I first wrote here; see the correction note at the end. Posting the numbers so the next person doesn't repeat the attempt.

What I measured

I instrumented finish_stage_ui to print the pane rect (ui.available_rect_before_wrap(), the value the button is positioned from) and read the button's own rect back through the accessibility tree, sweeping window sizes both with and without .constrain_to(viewport) on the Area:

window central pane (viewport) pane width Fit button, unfixed with constrain_to
1440×900 296 – 1096 800 1024 – 1088 unchanged
900×700 296 – 556 260 484 – 548 unchanged
720×600 296 – 376 80 304 – 368 unchanged
560×460 296 – 296 0 224 – 288 232 – 296
460×380 296 – 368 72 296 – 360 unchanged
380×320 296 – 372 76 300 – 364 unchanged
320×260 296 – 312 16 240 – 304 248 – 312

What this says

At every size where the pane can actually hold the button, fixed_pos(viewport.right_top() - 72) already places it inside the pane, and constrain_to changes nothing.

It does have an effect in the two degenerate rows: it shifts the button 8px so its right edge pins exactly to viewport.right (296 and 312). That is real clamping — but the pane there is 0px and 16px wide against a 64px button, so pinning the right edge just means the button still overhangs the other way. It is cosmetic in a layout that is already broken, and it does not address the reported symptom.

What the small-size rows actually show

The interesting column is pane width. The pane collapses because the two side panels do not yield:

egui::Panel::left("frames").default_size(288.0).min_size(240.0)
egui::Panel::right("inspector").min_size(260.0).max_size(560.0)

240 + 260 = 500px of panel minimums, with the left panel starting at x=296. Below roughly 800px of window width the central pane is squeezed to a sliver — at 560×460 it is literally zero width — and everything in it is mispositioned. The Fit button is just the most visible symptom. If this reproduces on a real low-resolution display, I would expect the whole Finish pane to look wrong, not only this button.

What would settle it

The report says "shifts position when resizing" and "misaligned relative to its container", and the evidence is a phone photo of the screen rather than a screenshot. Two things would pin it down:

  1. The window size / screen resolution where it misaligns — specifically whether the preview pane is still a usable width at that point.
  2. Whether the whole Finish pane is cramped in that state, or only the Fit button is out of place. That single detail separates "panel minimums collapse the pane" from "this one button is positioned wrong".

I have not changed any code — I would rather leave this open and correctly diagnosed than ship a change that closes it without fixing what you reported.


Correction: an earlier version of this comment claimed the button's rect was "byte-identical in every case" with and without constrain_to, and its 320×260 row mixed the unfixed button position against the fixed viewport. Both were wrong: two of the seven sizes do shift by 8px, as the table above now shows. The conclusion is unchanged, but the reasoning is not what I first posted.

Measured this in the `egui_kittest` harness. **`constrain_to` is not the fix** — but not for the reason I first wrote here; see the correction note at the end. Posting the numbers so the next person doesn't repeat the attempt. ## What I measured I instrumented `finish_stage_ui` to print the pane rect (`ui.available_rect_before_wrap()`, the value the button is positioned from) and read the button's own rect back through the accessibility tree, sweeping window sizes both with and without `.constrain_to(viewport)` on the `Area`: | window | central pane (`viewport`) | pane width | Fit button, unfixed | with `constrain_to` | | --- | --- | --- | --- | --- | | 1440×900 | 296 – 1096 | 800 | 1024 – 1088 | unchanged | | 900×700 | 296 – 556 | 260 | 484 – 548 | unchanged | | 720×600 | 296 – 376 | 80 | 304 – 368 | unchanged | | 560×460 | 296 – 296 | **0** | 224 – 288 | **232 – 296** | | 460×380 | 296 – 368 | 72 | 296 – 360 | unchanged | | 380×320 | 296 – 372 | 76 | 300 – 364 | unchanged | | 320×260 | 296 – 312 | **16** | 240 – 304 | **248 – 312** | ## What this says At every size where the pane can actually hold the button, `fixed_pos(viewport.right_top() - 72)` already places it **inside** the pane, and `constrain_to` changes nothing. It does have an effect in the two degenerate rows: it shifts the button 8px so its right edge pins exactly to `viewport.right` (296 and 312). That is real clamping — but the pane there is **0px and 16px wide** against a **64px** button, so pinning the right edge just means the button still overhangs the other way. It is cosmetic in a layout that is already broken, and it does not address the reported symptom. ## What the small-size rows actually show The interesting column is pane width. The pane collapses because the two side panels do not yield: ```rust egui::Panel::left("frames").default_size(288.0).min_size(240.0) egui::Panel::right("inspector").min_size(260.0).max_size(560.0) ``` 240 + 260 = 500px of panel minimums, with the left panel starting at x=296. Below roughly 800px of window width the central pane is squeezed to a sliver — at 560×460 it is literally **zero** width — and *everything* in it is mispositioned. The Fit button is just the most visible symptom. If this reproduces on a real low-resolution display, I would expect the whole Finish pane to look wrong, not only this button. ## What would settle it The report says "shifts position when resizing" and "misaligned relative to its container", and the evidence is a phone photo of the screen rather than a screenshot. Two things would pin it down: 1. The **window size / screen resolution** where it misaligns — specifically whether the preview pane is still a usable width at that point. 2. Whether the **whole Finish pane** is cramped in that state, or only the Fit button is out of place. That single detail separates "panel minimums collapse the pane" from "this one button is positioned wrong". I have not changed any code — I would rather leave this open and correctly diagnosed than ship a change that closes it without fixing what you reported. --- **Correction:** an earlier version of this comment claimed the button's rect was "byte-identical in every case" with and without `constrain_to`, and its 320×260 row mixed the unfixed button position against the fixed viewport. Both were wrong: two of the seven sizes do shift by 8px, as the table above now shows. The conclusion is unchanged, but the reasoning is not what I first posted.
Owner

Update: a related fix has landed, and on current main I can no longer make this happen. Leaving the ticket open, because "I can't reproduce it any more" is not the same as "what you saw is fixed" — and there is one gap I genuinely cannot test.

What changed

spikerj/spikersoft-stacker#570 stopped the preview pane collapsing. Re-measuring the Fit button against main after it:

window preview pane pane width Fit button inside its pane?
1440×900 296–1096 800 1024–1088 yes
900×700 296–640 344 568–632 yes
720×600 200–472 272 400–464 yes
560×460 8–312 304 (was 0) 240–304 yes
460×380 8–212 204 140–204 yes
380×320 8–156 148 84–148 yes
320×260 8–168 160 (was 16) 96–160 yes

Both cases where the button used to sit outside its pane are gone. The button needs 72px of pane; the narrowest pane the app can now produce is 148px, about double that.

I also tested the other theory from my earlier comment — that the button lags a frame behind a resize. Driving real resizes (1440→900→560→1440) and reading every frame, it is in the right place on the first frame each time. That mechanism is disproven, not just unobserved.

What I still cannot rule out

Everything above was measured at 100% display scaling. You are on Windows 11, where 125% or 150% scaling is common, and that is the one realistic path to a misplaced button I have no way to test here.

Two things that would close this out

  1. Please retest on a build that contains #570. Your report was against v2026.09.13, which predates it. There is a fair chance this is simply resolved for you.
  2. If you still see it, the useful detail is narrower than resolution: is the button misplaced when you are just looking at the window (not touching it), or only while you are actively dragging the window edge? A still screenshot of the misplaced state answers it. And if it is misplaced at rest, please tell me your Windows display scaling percentage (Settings → System → Display → Scale).

At-rest misplacement should now be impossible at any pane width above 72px. If you can still produce one, that points squarely at the scaling gap and I will go after it there.

Update: a related fix has landed, and on current `main` I can no longer make this happen. **Leaving the ticket open**, because "I can't reproduce it any more" is not the same as "what you saw is fixed" — and there is one gap I genuinely cannot test. ## What changed spikerj/spikersoft-stacker#570 stopped the preview pane collapsing. Re-measuring the Fit button against `main` after it: | window | preview pane | pane width | Fit button | inside its pane? | | --- | --- | --- | --- | --- | | 1440×900 | 296–1096 | 800 | 1024–1088 | yes | | 900×700 | 296–640 | 344 | 568–632 | yes | | 720×600 | 200–472 | 272 | 400–464 | yes | | 560×460 | 8–312 | **304** (was 0) | 240–304 | yes | | 460×380 | 8–212 | 204 | 140–204 | yes | | 380×320 | 8–156 | 148 | 84–148 | yes | | 320×260 | 8–168 | **160** (was 16) | 96–160 | yes | Both cases where the button used to sit outside its pane are gone. The button needs 72px of pane; the narrowest pane the app can now produce is 148px, about double that. I also tested the other theory from my earlier comment — that the button lags a frame behind a resize. Driving real resizes (1440→900→560→1440) and reading every frame, it is in the right place on the *first* frame each time. **That mechanism is disproven, not just unobserved.** ## What I still cannot rule out Everything above was measured at 100% display scaling. You are on Windows 11, where **125% or 150% scaling is common**, and that is the one realistic path to a misplaced button I have no way to test here. ## Two things that would close this out 1. **Please retest on a build that contains #570.** Your report was against v2026.09.13, which predates it. There is a fair chance this is simply resolved for you. 2. If you still see it, the useful detail is narrower than resolution: **is the button misplaced when you are just looking at the window (not touching it), or only while you are actively dragging the window edge?** A still screenshot of the misplaced state answers it. And if it is misplaced at rest, please tell me your **Windows display scaling percentage** (Settings → System → Display → Scale). At-rest misplacement should now be impossible at any pane width above 72px. If you can still produce one, that points squarely at the scaling gap and I will go after it there.
Sign in to join this conversation.