The setup menu flows into as many columns as it needs
I fixed the wrong column twice. The overflow was never the vehicle list: it was the settings column - scenario, map, time, weather, length - which sat within 11px of the bottom at 800x600 before any of this, and went 115px past it once seven maps were added. At 1080p it wanted 1174 of 1080. Fixed columns cannot hold this menu any more, so the groups flow: they fill a column, start the next, and the layout takes as many as the content needs, sizing them to share the width. Two passes - one to count the columns, one to place the items - so nothing has to know the count in advance. Adding a map or a vehicle can no longer push anything off screen, which is the actual property that was missing. Every column starts two rows down so the pilot name box has the same home whichever column ends up last, and the bottom is reserved for LAUNCH and the lobby buttons. AddGroupItems is gone; the flow places items directly. Verified by arithmetic at 640x480, 800x600, 1024x768, 1280x720 and 1920x1080 in both scenarios - nothing exceeds its width or its bottom - and by running the front end at four of those plus a mission at 800x600. 800x600 is honestly dense: the content genuinely needs five columns there, and the longest few names ellipsize. Lowering the row-height floor does not buy a column back, so the rows stay at 18px and legible. Dropdowns would end this class of problem outright and are worth considering. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+89
-84
@@ -612,26 +612,6 @@ namespace
|
||||
//---------------------------------------------------------------
|
||||
// Layout: three columns of lists + the launch button
|
||||
//---------------------------------------------------------------
|
||||
// 'first' is the index of the group's own list to start at, so a long
|
||||
// group can be laid out as several columns; the items stay contiguous
|
||||
// in fe->items, so the header still draws once, above the first one.
|
||||
void AddGroupItems(
|
||||
FEState *fe, int group, int count,
|
||||
int x, int *y, int row_h, int width, int first = 0)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
FEItem *item = &fe->items[fe->itemCount++];
|
||||
item->group = group;
|
||||
item->index = first + i;
|
||||
item->rect.left = x;
|
||||
item->rect.top = *y;
|
||||
item->rect.right = x + width;
|
||||
item->rect.bottom = *y + row_h;
|
||||
*y += row_h;
|
||||
}
|
||||
*y += row_h; // gap below the group
|
||||
}
|
||||
|
||||
void LayoutMenu(FEState *fe, int client_w, int client_h)
|
||||
{
|
||||
@@ -644,79 +624,104 @@ namespace
|
||||
int top = client_h / 7;
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// The vehicle list outgrew one column when the promoted resource
|
||||
// file brought eleven more machines: at 1080p it ran a couple of
|
||||
// hundred pixels past the bottom of the window. Wrap it over two
|
||||
// columns rather than shrinking rows below the 18px floor, and
|
||||
// shift the loadout column (and the buttons that live with it)
|
||||
// one place right. A roster short enough for one column lays out
|
||||
// exactly as it always did.
|
||||
// Fixed columns cannot hold this menu any more. The promoted
|
||||
// resource file brought eleven vehicles and seven maps, and the
|
||||
// settings column - scenario, map, time, weather, length - was
|
||||
// already within 11px of the bottom at 800x600 before any of
|
||||
// them arrived. So the groups FLOW: they fill a column, then
|
||||
// start the next, and the layout takes as many columns as the
|
||||
// content needs. Nothing here knows how many that will be, which
|
||||
// is the point - adding a map or a vehicle can no longer push
|
||||
// anything off the screen.
|
||||
//---------------------------------------------------------------
|
||||
int rows_per_col = (client_h - top - 3 * row_h) / row_h;
|
||||
if (rows_per_col < 1) rows_per_col = 1;
|
||||
|
||||
int vehicle_count = FE_COUNT(kVehicles);
|
||||
Logical wrap_vehicles = (vehicle_count > rows_per_col);
|
||||
int vehicle_split = wrap_vehicles
|
||||
? (vehicle_count + 1) / 2 // balanced, not filled-then-spilled
|
||||
: vehicle_count;
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Three columns can afford generous margins; four cannot. Keeping
|
||||
// the three-column fractions for a fourth column left the last one
|
||||
// hard against the frame - 19px of slack at 800x600, with the
|
||||
// longest vehicle name needing all but 2px of its column. So the
|
||||
// wrapped layout spreads its four columns evenly instead, and the
|
||||
// unwrapped one keeps the proportions it always had.
|
||||
//---------------------------------------------------------------
|
||||
int col_w, col1, gap;
|
||||
if (wrap_vehicles)
|
||||
{
|
||||
col1 = client_w / 20;
|
||||
gap = client_w / 50;
|
||||
col_w = (client_w - 2 * col1 - 3 * gap) / 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
col1 = client_w / 14;
|
||||
gap = client_w / 28;
|
||||
col_w = client_w / 5;
|
||||
}
|
||||
int col2 = col1 + col_w + gap;
|
||||
int col3 = col2 + col_w + gap;
|
||||
int col4 = col3 + col_w + gap;
|
||||
int loadout_col = wrap_vehicles ? col4 : col3;
|
||||
|
||||
int y = top;
|
||||
AddGroupItems(fe, GroupScenario, FE_COUNT(kScenarios), col1, &y, row_h, col_w);
|
||||
int map_count;
|
||||
ActiveMaps(fe->selection, &map_count);
|
||||
AddGroupItems(fe, GroupMap, map_count, col1, &y, row_h, col_w);
|
||||
AddGroupItems(fe, GroupTime, FE_COUNT(kTimes), col1, &y, row_h, col_w);
|
||||
AddGroupItems(fe, GroupWeather, FE_COUNT(kWeather), col1, &y, row_h, col_w);
|
||||
AddGroupItems(fe, GroupLength, FE_COUNT(kLengths), col1, &y, row_h, col_w);
|
||||
|
||||
y = top;
|
||||
AddGroupItems(fe, GroupVehicle, vehicle_split, col2, &y, row_h, col_w);
|
||||
if (wrap_vehicles)
|
||||
{
|
||||
y = top;
|
||||
AddGroupItems(fe, GroupVehicle, vehicle_count - vehicle_split,
|
||||
col3, &y, row_h, col_w, vehicle_split);
|
||||
}
|
||||
|
||||
y = top + 2 * row_h; // leave room for the name edit + header
|
||||
struct FlowGroup { int group; int count; };
|
||||
FlowGroup flow[8];
|
||||
int flow_count = 0;
|
||||
flow[flow_count].group = GroupScenario;
|
||||
flow[flow_count++].count = FE_COUNT(kScenarios);
|
||||
flow[flow_count].group = GroupMap;
|
||||
flow[flow_count++].count = map_count;
|
||||
flow[flow_count].group = GroupTime;
|
||||
flow[flow_count++].count = FE_COUNT(kTimes);
|
||||
flow[flow_count].group = GroupWeather;
|
||||
flow[flow_count++].count = FE_COUNT(kWeather);
|
||||
flow[flow_count].group = GroupLength;
|
||||
flow[flow_count++].count = FE_COUNT(kLengths);
|
||||
flow[flow_count].group = GroupVehicle;
|
||||
flow[flow_count++].count = FE_COUNT(kVehicles);
|
||||
if (IsFootball(fe->selection))
|
||||
{
|
||||
AddGroupItems(fe, GroupTeam, FE_COUNT(kTeams), loadout_col, &y, row_h, col_w);
|
||||
AddGroupItems(fe, GroupPosition, FE_COUNT(kPositions), loadout_col, &y, row_h, col_w);
|
||||
flow[flow_count].group = GroupTeam;
|
||||
flow[flow_count++].count = FE_COUNT(kTeams);
|
||||
flow[flow_count].group = GroupPosition;
|
||||
flow[flow_count++].count = FE_COUNT(kPositions);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddGroupItems(fe, GroupColor, FE_COUNT(kColors), loadout_col, &y, row_h, col_w);
|
||||
AddGroupItems(fe, GroupBadge, FE_COUNT(kBadges), loadout_col, &y, row_h, col_w);
|
||||
flow[flow_count].group = GroupColor;
|
||||
flow[flow_count++].count = FE_COUNT(kColors);
|
||||
flow[flow_count].group = GroupBadge;
|
||||
flow[flow_count++].count = FE_COUNT(kBadges);
|
||||
}
|
||||
|
||||
// Every column starts two rows down so the pilot name box has the
|
||||
// same home on whichever column ends up last, and they all line
|
||||
// up. The bottom is reserved for LAUNCH and the lobby buttons.
|
||||
int content_top = top + 2 * row_h;
|
||||
int bottom = client_h - (RPL4Lobby_Configured() ? 7 : 4) * row_h;
|
||||
int rows_per_col = (bottom - content_top) / row_h;
|
||||
if (rows_per_col < 1) rows_per_col = 1;
|
||||
|
||||
// Pass one: how many columns does this content want? A group is
|
||||
// preceded by a blank row unless it lands at the top of a column,
|
||||
// and a group longer than a column simply continues into the next.
|
||||
int columns = 1;
|
||||
{
|
||||
int row = 0;
|
||||
for (int g = 0; g < flow_count; ++g)
|
||||
{
|
||||
if (row > 0) ++row;
|
||||
for (int i = 0; i < flow[g].count; ++i)
|
||||
{
|
||||
if (row >= rows_per_col) { ++columns; row = 0; }
|
||||
++row;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int margin = client_w / 20;
|
||||
int gap = client_w / 50;
|
||||
int col_w = (client_w - 2 * margin - (columns - 1) * gap) / columns;
|
||||
if (col_w < 1) col_w = 1;
|
||||
|
||||
// Pass two: the same walk, placing items this time.
|
||||
int last_col = 0;
|
||||
{
|
||||
int column = 0, row = 0;
|
||||
for (int g = 0; g < flow_count; ++g)
|
||||
{
|
||||
if (row > 0) ++row;
|
||||
for (int i = 0; i < flow[g].count; ++i)
|
||||
{
|
||||
if (row >= rows_per_col) { ++column; row = 0; }
|
||||
FEItem *item = &fe->items[fe->itemCount++];
|
||||
item->group = flow[g].group;
|
||||
item->index = i;
|
||||
item->rect.left = margin + column * (col_w + gap);
|
||||
item->rect.top = content_top + row * row_h;
|
||||
item->rect.right = item->rect.left + col_w;
|
||||
item->rect.bottom = item->rect.top + row_h;
|
||||
++row;
|
||||
}
|
||||
last_col = column;
|
||||
}
|
||||
}
|
||||
|
||||
int loadout_col = margin + last_col * (col_w + gap);
|
||||
|
||||
// launch button
|
||||
FEItem *launch = &fe->items[fe->itemCount++];
|
||||
launch->group = GroupLaunch;
|
||||
@@ -759,9 +764,9 @@ namespace
|
||||
FEItem *quit = &fe->items[fe->itemCount++];
|
||||
quit->group = GroupExit;
|
||||
quit->index = 0;
|
||||
quit->rect.left = col1;
|
||||
quit->rect.left = margin;
|
||||
quit->rect.top = client_h - 2 * row_h;
|
||||
quit->rect.right = col1 + col_w / 2;
|
||||
quit->rect.right = margin + col_w / 2;
|
||||
quit->rect.bottom = client_h - row_h;
|
||||
|
||||
// pilot name edit sits at the top of column 3
|
||||
|
||||
Reference in New Issue
Block a user