diff --git a/RP_L4/RPL4FE.cpp b/RP_L4/RPL4FE.cpp index 23ce769..6c20b78 100644 --- a/RP_L4/RPL4FE.cpp +++ b/RP_L4/RPL4FE.cpp @@ -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