Skip to content

Commit 9635c7b

Browse files
committed
Centre the digit field in the space it actually has
The field sat 13px above the centre of the band between its title and its footer - measured, not eyeballed: the stack of arrows and boxes ran 26..77, centre 51, in a band of 18..110 whose centre is 64. DIGIT_BOX_Y and the two arrow rows were pinned literals, so nothing moved when the arrows changed height and nothing could notice they were off-centre to begin with. They are derived from the stack's own parts now, and from the band it sits in. That band is not the same on both screens that draw this stack, which is why one pinned y could never suit both: the digit field has only the footer under it, while the value box shares its screen with the entropy quality bar at DICE_BAR_Y. Each centres against the thing that actually bounds it. The value box moves down 2px as a result - it was not centred above the bar either, just less visibly. Two things this turned up: The assert meant to keep the down arrow off the footer compared against LIST_FOOTER_Y, which belongs to the list screens and sits 11px below the footer these actually draw. It would have permitted the overlap it was written to catch. Both placements are asserted now, each against its own bound. The footer's y was the literal 111 in three renderers; it is SCREEN_FOOTER_Y, which is what the centring has to measure against. Verified with the host self-test and the 52 Python tests, and by measuring the rendered framebuffer: the stack now centres at 63 against the band's 64, the 1px being the odd height's rounding.
1 parent 0d25db1 commit 9635c7b

1 file changed

Lines changed: 54 additions & 23 deletions

File tree

‎main/seedtool_render.c‎

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@
4848
#define LIST_TOP 21
4949
#define LIST_ROW_HEIGHT 33
5050
#define LIST_FOOTER_Y 122
51+
52+
/* The plain screens put their title at the top and their footer near the
53+
* bottom; the band between is what the screen is for. Named because the digit
54+
* field centres itself in it. */
55+
#define SCREEN_TITLE_Y 2
56+
#define SCREEN_TITLE_BOTTOM (SCREEN_TITLE_Y + 16) /* the 16px face's own height */
57+
#define SCREEN_FOOTER_Y 111
5158
#define LIST_GUTTER 10
5259
#define LIST_BAR_X 2
5360
#define LIST_BAR_WIDTH (SEEDTOOL_DISPLAY_WIDTH - LIST_GUTTER - 2 * LIST_BAR_X)
@@ -434,7 +441,7 @@ void seedtool_render_screen(const char* title, const char* line1, const char* li
434441
* small because 16px there would run off the bottom of the display. */
435442
draw_centered(tft_Ubuntu16, line1, 39);
436443
draw_centered(tft_Ubuntu16, line2, 65);
437-
draw_centered(tft_DefaultFont, footer, 111);
444+
draw_centered(tft_DefaultFont, footer, SCREEN_FOOTER_Y);
438445
}
439446

440447
seedtool_thumb_t seedtool_list_thumb(const size_t count, const size_t top, const int track)
@@ -852,15 +859,23 @@ static void draw_progress_bar(const seedtool_progress_t* progress)
852859
#define DIGIT_BOX_WIDTH 34
853860
#define DIGIT_BOX_HEIGHT 32
854861
#define DIGIT_BOX_GAP 6
855-
#define DIGIT_BOX_Y 36
856862
#define DIGIT_ARROW_WIDTH 11
857863
/* Six rows, not seven: the half-width steps in whole pixels, so an 11-wide
858864
* triangle has exactly six distinct rows (1, 3, 5, 7, 9, 11). A seventh row
859865
* has no width left of its own and repeats one, which reads as a flat spot in
860866
* the edge rather than a straight diagonal. */
861867
#define DIGIT_ARROW_HEIGHT 6
862-
#define DIGIT_ARROW_UP_Y 26
863-
#define DIGIT_ARROW_DOWN_Y 71
868+
869+
/* An arrow, the boxes, an arrow: one stack, sitting at a different height on
870+
* each screen that draws it because what is under it differs - the value box
871+
* shares its screen with the entropy quality bar, the digit field has only the
872+
* footer. Derived from the stack's own parts, so changing an arrow's height
873+
* moves the stack rather than silently unbalancing it. */
874+
#define DIGIT_FIELD_GAP 4
875+
#define DIGIT_FIELD_HEIGHT (2 * (DIGIT_ARROW_HEIGHT + DIGIT_FIELD_GAP) + DIGIT_BOX_HEIGHT)
876+
#define DIGIT_FIELD_TOP(bottom) (SCREEN_TITLE_BOTTOM + ((bottom) -SCREEN_TITLE_BOTTOM - DIGIT_FIELD_HEIGHT) / 2)
877+
#define DIGIT_FIELD_BOX_Y(top) ((top) + DIGIT_ARROW_HEIGHT + DIGIT_FIELD_GAP)
878+
#define DIGIT_FIELD_DOWN_Y(top) (DIGIT_FIELD_BOX_Y(top) + DIGIT_BOX_HEIGHT + DIGIT_FIELD_GAP)
864879

865880
/* Held rather than eyeballed. The widest field is one box per digit a word
866881
* number can have, and it is centred, so a box or gap grown by a few pixels
@@ -871,9 +886,14 @@ static void draw_progress_bar(const seedtool_progress_t* progress)
871886
_Static_assert(SEEDTOOL_DIGIT_BOXES_MAX * DIGIT_BOX_WIDTH + (SEEDTOOL_DIGIT_BOXES_MAX - 1) * DIGIT_BOX_GAP
872887
<= SEEDTOOL_DISPLAY_WIDTH,
873888
"the digit boxes are wider than the display");
874-
_Static_assert(DIGIT_ARROW_UP_Y + DIGIT_ARROW_HEIGHT <= DIGIT_BOX_Y, "the up arrow runs into the digit boxes");
875-
_Static_assert(DIGIT_BOX_Y + DIGIT_BOX_HEIGHT <= DIGIT_ARROW_DOWN_Y, "the digit boxes run into the down arrow");
876-
_Static_assert(DIGIT_ARROW_DOWN_Y + DIGIT_ARROW_HEIGHT <= LIST_FOOTER_Y, "the down arrow runs into the footer");
889+
/* Both placements, each against the thing that actually bounds it. */
890+
_Static_assert(DIGIT_FIELD_TOP(SCREEN_FOOTER_Y) >= SCREEN_TITLE_BOTTOM, "the digit field runs into the title");
891+
_Static_assert(DIGIT_FIELD_DOWN_Y(DIGIT_FIELD_TOP(SCREEN_FOOTER_Y)) + DIGIT_ARROW_HEIGHT <= SCREEN_FOOTER_Y,
892+
"the digit field runs into the footer");
893+
_Static_assert(DIGIT_FIELD_TOP(DICE_BAR_Y) >= SCREEN_TITLE_BOTTOM, "the value box runs into the title");
894+
_Static_assert(DIGIT_FIELD_DOWN_Y(DIGIT_FIELD_TOP(DICE_BAR_Y)) + DIGIT_ARROW_HEIGHT <= DICE_BAR_Y,
895+
"the value box runs into the quality bar");
896+
877897

878898
/* One wider box for a value scrolled whole rather than digit by digit: a die
879899
* face is 1-6 and a D20 is 1-20, so splitting it into per-digit boxes would
@@ -885,21 +905,27 @@ void seedtool_render_value_box(
885905
const char* title, const char* text, const bool back, const char* footer, const seedtool_progress_t* progress)
886906
{
887907
seedtool_render_clear();
888-
draw_centered(tft_Ubuntu16, title, 2);
908+
draw_centered(tft_Ubuntu16, title, SCREEN_TITLE_Y);
909+
/* Centred above the quality bar, not the footer: the bar is what shares
910+
* this screen, whether or not `progress` draws one this time - the box
911+
* should not jump between runs that grade their entropy and runs that do
912+
* not. */
913+
const int top = DIGIT_FIELD_TOP(DICE_BAR_Y);
914+
const int box_y = DIGIT_FIELD_BOX_Y(top);
889915
const int x = (SEEDTOOL_DISPLAY_WIDTH - VALUE_BOX_WIDTH) / 2;
890-
fill_rect(x, DIGIT_BOX_Y, VALUE_BOX_WIDTH, DIGIT_BOX_HEIGHT, COLOR_HIGHLIGHT);
891-
draw_border(x, DIGIT_BOX_Y, VALUE_BOX_WIDTH, DIGIT_BOX_HEIGHT, COLOR_HIGHLIGHT);
916+
fill_rect(x, box_y, VALUE_BOX_WIDTH, DIGIT_BOX_HEIGHT, COLOR_HIGHLIGHT);
917+
draw_border(x, box_y, VALUE_BOX_WIDTH, DIGIT_BOX_HEIGHT, COLOR_HIGHLIGHT);
892918
if (back) {
893919
draw_backspace(x + (VALUE_BOX_WIDTH - BACKSPACE_WIDTH) / 2,
894-
DIGIT_BOX_Y + (DIGIT_BOX_HEIGHT - BACKSPACE_HEIGHT) / 2, COLOR_BLACK, COLOR_HIGHLIGHT);
920+
box_y + (DIGIT_BOX_HEIGHT - BACKSPACE_HEIGHT) / 2, COLOR_BLACK, COLOR_HIGHLIGHT);
895921
} else {
896922
draw_centered_in(tft_Ubuntu16, text, x, VALUE_BOX_WIDTH,
897-
DIGIT_BOX_Y + (DIGIT_BOX_HEIGHT - tft_Ubuntu16[1]) / 2, COLOR_BLACK);
923+
box_y + (DIGIT_BOX_HEIGHT - tft_Ubuntu16[1]) / 2, COLOR_BLACK);
898924
}
899925
const int arrow_x = x + (VALUE_BOX_WIDTH - DIGIT_ARROW_WIDTH) / 2;
900-
draw_triangle(arrow_x, DIGIT_ARROW_UP_Y, DIGIT_ARROW_WIDTH, DIGIT_ARROW_HEIGHT, TRIANGLE_UP, COLOR_WHITE);
901-
draw_triangle(arrow_x, DIGIT_ARROW_DOWN_Y, DIGIT_ARROW_WIDTH, DIGIT_ARROW_HEIGHT, TRIANGLE_DOWN, COLOR_WHITE);
902-
draw_centered(tft_DefaultFont, footer, 111);
926+
draw_triangle(arrow_x, top, DIGIT_ARROW_WIDTH, DIGIT_ARROW_HEIGHT, TRIANGLE_UP, COLOR_WHITE);
927+
draw_triangle(arrow_x, DIGIT_FIELD_DOWN_Y(top), DIGIT_ARROW_WIDTH, DIGIT_ARROW_HEIGHT, TRIANGLE_DOWN, COLOR_WHITE);
928+
draw_centered(tft_DefaultFont, footer, SCREEN_FOOTER_Y);
903929
if (progress) {
904930
draw_progress_bar(progress);
905931
}
@@ -909,29 +935,33 @@ void seedtool_render_digits(const char* title, const char* digits, const size_t
909935
const char* footer, const seedtool_progress_t* progress)
910936
{
911937
seedtool_render_clear();
912-
draw_centered(tft_Ubuntu16, title, 2);
938+
draw_centered(tft_Ubuntu16, title, SCREEN_TITLE_Y);
913939

940+
/* Nothing under this field but the footer, so it centres in that whole
941+
* band rather than sharing the value box's higher placement. */
942+
const int top = DIGIT_FIELD_TOP(SCREEN_FOOTER_Y);
943+
const int box_y = DIGIT_FIELD_BOX_Y(top);
914944
const int span = (int)count * DIGIT_BOX_WIDTH + ((int)count - 1) * DIGIT_BOX_GAP;
915945
const int left = (SEEDTOOL_DISPLAY_WIDTH - span) / 2;
916946
for (size_t i = 0; i < count; ++i) {
917947
const int x = left + (int)i * (DIGIT_BOX_WIDTH + DIGIT_BOX_GAP);
918948
const bool selected = i == active;
919949
const bool set = i < active;
920950
if (selected) {
921-
fill_rect(x, DIGIT_BOX_Y, DIGIT_BOX_WIDTH, DIGIT_BOX_HEIGHT, COLOR_HIGHLIGHT);
951+
fill_rect(x, box_y, DIGIT_BOX_WIDTH, DIGIT_BOX_HEIGHT, COLOR_HIGHLIGHT);
922952
}
923-
draw_border(x, DIGIT_BOX_Y, DIGIT_BOX_WIDTH, DIGIT_BOX_HEIGHT,
953+
draw_border(x, box_y, DIGIT_BOX_WIDTH, DIGIT_BOX_HEIGHT,
924954
selected ? COLOR_HIGHLIGHT : set ? COLOR_WHITE : COLOR_DIM);
925955

926956
const char shown = digits[i];
927-
const int glyph_y = DIGIT_BOX_Y + (DIGIT_BOX_HEIGHT - tft_Ubuntu16[1]) / 2;
957+
const int glyph_y = box_y + (DIGIT_BOX_HEIGHT - tft_Ubuntu16[1]) / 2;
928958
if (shown == SEEDTOOL_KEY_ACCEPT) {
929959
draw_centered_in(tft_Ubuntu16, "OK", x, DIGIT_BOX_WIDTH, glyph_y, selected ? COLOR_BLACK : COLOR_WHITE);
930960
} else if (shown == SEEDTOOL_KEY_BACKSPACE) {
931961
/* The way out of the field rides the same ring as the digits, so
932962
* the box shows the backspace glyph the keypad already uses for
933963
* it rather than a letter the reader has to decode. */
934-
draw_backspace(x + (DIGIT_BOX_WIDTH - BACKSPACE_WIDTH) / 2, DIGIT_BOX_Y + (DIGIT_BOX_HEIGHT - BACKSPACE_HEIGHT) / 2,
964+
draw_backspace(x + (DIGIT_BOX_WIDTH - BACKSPACE_WIDTH) / 2, box_y + (DIGIT_BOX_HEIGHT - BACKSPACE_HEIGHT) / 2,
935965
COLOR_BLACK, COLOR_HIGHLIGHT);
936966
} else if (shown && shown != ' ') {
937967
const char text[2] = { shown, '\0' };
@@ -940,12 +970,13 @@ void seedtool_render_digits(const char* title, const char* digits, const size_t
940970

941971
if (selected) {
942972
const int arrow_x = x + (DIGIT_BOX_WIDTH - DIGIT_ARROW_WIDTH) / 2;
943-
draw_triangle(arrow_x, DIGIT_ARROW_UP_Y, DIGIT_ARROW_WIDTH, DIGIT_ARROW_HEIGHT, TRIANGLE_UP, COLOR_WHITE);
944-
draw_triangle(arrow_x, DIGIT_ARROW_DOWN_Y, DIGIT_ARROW_WIDTH, DIGIT_ARROW_HEIGHT, TRIANGLE_DOWN, COLOR_WHITE);
973+
draw_triangle(arrow_x, top, DIGIT_ARROW_WIDTH, DIGIT_ARROW_HEIGHT, TRIANGLE_UP, COLOR_WHITE);
974+
draw_triangle(
975+
arrow_x, DIGIT_FIELD_DOWN_Y(top), DIGIT_ARROW_WIDTH, DIGIT_ARROW_HEIGHT, TRIANGLE_DOWN, COLOR_WHITE);
945976
}
946977
}
947978

948-
draw_centered(tft_DefaultFont, footer, 111);
979+
draw_centered(tft_DefaultFont, footer, SCREEN_FOOTER_Y);
949980
if (progress) {
950981
draw_progress_bar(progress);
951982
}

0 commit comments

Comments
 (0)