Reserve the display's space so the keypad stops moving
The pending-operation line was only described when there was a pending operation, so pressing an operator grew the display block by a row and pushed the keypad down — the view jumped on every sum. The row is now always emitted, empty when there is nothing to say, and both it and the value have a fixed height. The keypad's own height is derived from that same constant, so the two cannot drift apart. Nim only: no library change, so no release. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
a561f5a parent: 2460321 modified
examples/calculator.nim +13 -4 | @@ -27,6 +27,10 @@ type | ||
| 27 | 27 | const |
| 28 | 28 | Cols = 4 |
| 29 | 29 | Rows = 5 |
| 30 | + # The display block is a fixed height whatever it contains, so the keypad | |
| 31 | + # does not walk up and down as the pending-operation line comes and goes. | |
| 32 | + CaptionH = 26.0 | |
| 33 | + ValueH = 64.0 | |
| 30 | 34 | MinKeyW = 56.0 |
| 31 | 35 | MinKeyH = 44.0 |
| 32 | 36 | |
| @@ -192,7 +196,7 @@ proc onView(ctx: pointer; b: Builder; width, height: cfloat) {.cdecl.} = | ||
| 192 | 196 | let |
| 193 | 197 | gap = space(SpaceXs) |
| 194 | 198 | pad = space(SpaceM) |
| 195 | - display = 96.0 | |
| 199 | + display = CaptionH + ValueH | |
| 196 | 200 | # A dimension that is not a sane finite number means the library could not |
| 197 | 201 | # say, so fall back to the size the config asked for rather than dividing |
| 198 | 202 | # by infinity and collapsing every key to its floor. |
| @@ -207,10 +211,15 @@ proc onView(ctx: pointer; b: Builder; width, height: cfloat) {.cdecl.} = | ||
| 207 | 211 | b.alignCenter() |
| 208 | 212 | b.spacing(space(SpaceM)) |
| 209 | 213 | |
| 210 | - # The pending operation only exists as a line when there is one. | |
| 211 | - if c.pending != opNone and not c.error: | |
| 212 | - b.text(&"{format(c.acc)} {c.pending}", TextCaption) | |
| 214 | + # Always emitted, empty when there is nothing pending: the row has to | |
| 215 | + # occupy its space either way or the whole keypad shifts. | |
| 216 | + b.size(-1.0, CaptionH) | |
| 217 | + b.text( | |
| 218 | + if c.pending != opNone and not c.error: &"{format(c.acc)} {c.pending}" | |
| 219 | + else: "", | |
| 220 | + TextCaption) | |
| 213 | 221 | |
| 222 | + b.size(-1.0, ValueH) | |
| 214 | 223 | b.text(c[].display, TextTitle1) |
| 215 | 224 | |
| 216 | 225 | b.column: |
| @@ -27,6 +27,10 @@ type | |||
| 27 | const | 27 | const |
| 28 | Cols = 4 | 28 | Cols = 4 |
| 29 | Rows = 5 | 29 | Rows = 5 |
| 30 | + # The display block is a fixed height whatever it contains, so the keypad | ||
| 31 | + # does not walk up and down as the pending-operation line comes and goes. | ||
| 32 | + CaptionH = 26.0 | ||
| 33 | + ValueH = 64.0 | ||
| 30 | MinKeyW = 56.0 | 34 | MinKeyW = 56.0 |
| 31 | MinKeyH = 44.0 | 35 | MinKeyH = 44.0 |
| 32 | 36 | ||
| @@ -192,7 +196,7 @@ proc onView(ctx: pointer; b: Builder; width, height: cfloat) {.cdecl.} = | |||
| 192 | let | 196 | let |
| 193 | gap = space(SpaceXs) | 197 | gap = space(SpaceXs) |
| 194 | pad = space(SpaceM) | 198 | pad = space(SpaceM) |
| 195 | - display = 96.0 | 199 | + display = CaptionH + ValueH |
| 196 | # A dimension that is not a sane finite number means the library could not | 200 | # A dimension that is not a sane finite number means the library could not |
| 197 | # say, so fall back to the size the config asked for rather than dividing | 201 | # say, so fall back to the size the config asked for rather than dividing |
| 198 | # by infinity and collapsing every key to its floor. | 202 | # by infinity and collapsing every key to its floor. |
| @@ -207,10 +211,15 @@ proc onView(ctx: pointer; b: Builder; width, height: cfloat) {.cdecl.} = | |||
| 207 | b.alignCenter() | 211 | b.alignCenter() |
| 208 | b.spacing(space(SpaceM)) | 212 | b.spacing(space(SpaceM)) |
| 209 | 213 | ||
| 210 | - # The pending operation only exists as a line when there is one. | 214 | + # Always emitted, empty when there is nothing pending: the row has to |
| 211 | - if c.pending != opNone and not c.error: | 215 | + # occupy its space either way or the whole keypad shifts. |
| 212 | - b.text(&"{format(c.acc)} {c.pending}", TextCaption) | 216 | + b.size(-1.0, CaptionH) |
| 217 | + b.text( | ||
| 218 | + if c.pending != opNone and not c.error: &"{format(c.acc)} {c.pending}" | ||
| 219 | + else: "", | ||
| 220 | + TextCaption) | ||
| 213 | 221 | ||
| 222 | + b.size(-1.0, ValueH) | ||
| 214 | b.text(c[].display, TextTitle1) | 223 | b.text(c[].display, TextTitle1) |
| 215 | 224 | ||
| 216 | b.column: | 225 | b.column: |