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
440447seedtool_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