1
0
mirror of https://github.com/OpenTTD/OpenTTD.git synced 2025-08-12 17:19:09 +00:00

Change: Don't allow station/roadstop/object picker text to extend width.

Some NewGRF stations/roadstops/objects use very long strings for class or type names, which results in a very wide window.

Instead, truncate or wrap the text as appropriate.
This commit is contained in:
2023-12-19 20:21:41 +00:00
parent 934545a674
commit 5f591d28ae
3 changed files with 123 additions and 78 deletions

View File

@@ -52,6 +52,7 @@ class BuildObjectWindow : public Window {
int object_margin; ///< The margin (in pixels) around an object.
int line_height; ///< The height of a single line.
int info_height; ///< The height of the info box.
Dimension name; ///< Dimensions of object type name widget.
Scrollbar *vscroll; ///< The scrollbar.
static Listing last_sorting; ///< Default sorting of #GUIObjectClassList.
@@ -187,13 +188,6 @@ public:
void SetStringParameters(WidgetID widget) const override
{
switch (widget) {
case WID_BO_OBJECT_NAME: {
ObjectClass *objclass = ObjectClass::Get(_selected_object_class);
const ObjectSpec *spec = objclass->GetSpec(_selected_object_index);
SetDParam(0, spec != nullptr ? spec->name : STR_EMPTY);
break;
}
case WID_BO_OBJECT_SIZE: {
ObjectClass *objclass = ObjectClass::Get(_selected_object_class);
const ObjectSpec *spec = objclass->GetSpec(_selected_object_index);
@@ -216,11 +210,6 @@ public:
{
switch (widget) {
case WID_BO_CLASS_LIST: {
for (auto object_class_id : this->object_classes) {
ObjectClass *objclass = ObjectClass::Get(object_class_id);
if (objclass->GetUISpecCount() == 0) continue;
size->width = std::max(size->width, GetStringBoundingBox(objclass->name).width + padding.width);
}
this->line_height = GetCharacterHeight(FS_NORMAL) + padding.height;
resize->height = this->line_height;
size->height = 5 * this->line_height;
@@ -321,6 +310,12 @@ public:
break;
}
case WID_BO_OBJECT_NAME: {
const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index);
if (spec != nullptr) DrawStringMultiLine(r, spec->name, TC_ORANGE, SA_CENTER);
break;
}
case WID_BO_OBJECT_SPRITE: {
if (_selected_object_index == -1) break;
@@ -490,9 +485,29 @@ public:
this->BuildObjectClassesAvailable();
}
/**
* Get dimensions in pixels of object type names for the given width.
* @param width Width of text in pixels.
* @returns Dimensions required for object type name.
*/
Dimension GetObjectTypeNameDimension(int width) const
{
int y = 0;
for (const ObjectSpec &spec : ObjectSpec::Specs()) {
if (!spec.IsEverAvailable()) continue;
y = std::max(y, GetStringHeight(spec.name, width));
}
return Dimension(width, y);
}
void OnResize() override
{
this->vscroll->SetCapacityFromWidget(this, WID_BO_CLASS_LIST);
/* Update height of text for object type name widget if its width has changed. */
NWidgetResizeBase *wid = this->GetWidget<NWidgetResizeBase>(WID_BO_OBJECT_NAME);
if (this->name.width != wid->current_x) this->name = this->GetObjectTypeNameDimension(wid->current_x);
if (wid->UpdateVerticalSize(this->name.height)) this->ReInit(0, 0);
}
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
@@ -689,7 +704,7 @@ static const NWidgetPart _nested_build_object_widgets[] = {
NWidget(WWT_PANEL, COLOUR_GREY, WID_BO_OBJECT_SPRITE), SetDataTip(0x0, STR_OBJECT_BUILD_PREVIEW_TOOLTIP), EndContainer(),
EndContainer(),
EndContainer(),
NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_BO_OBJECT_NAME), SetDataTip(STR_JUST_STRING, STR_NULL), SetTextStyle(TC_ORANGE), SetAlignment(SA_CENTER),
NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_BO_OBJECT_NAME),
NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_BO_OBJECT_SIZE), SetDataTip(STR_OBJECT_BUILD_SIZE, STR_NULL), SetAlignment(SA_CENTER),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BO_SELECT_SCROLL),

View File

@@ -900,6 +900,7 @@ struct BuildRailStationWindow : public PickerWindowBase {
private:
uint line_height; ///< Height of a single line in the newstation selection matrix (#WID_BRAS_NEWST_LIST widget).
uint coverage_height; ///< Height of the coverage texts.
Dimension name; ///< Dimensions of station type name widget.
Scrollbar *vscroll; ///< Vertical scrollbar of the new station list.
Scrollbar *vscroll2; ///< Vertical scrollbar of the matrix with new stations.
@@ -1185,11 +1186,6 @@ public:
{
switch (widget) {
case WID_BRAS_NEWST_LIST: {
Dimension d = {0, 0};
for (auto station_class : this->station_classes) {
d = maxdim(d, GetStringBoundingBox(StationClass::Get(station_class)->name));
}
size->width = std::max(size->width, d.width + padding.width);
this->line_height = GetCharacterHeight(FS_NORMAL) + padding.height;
size->height = 5 * this->line_height;
resize->height = this->line_height;
@@ -1197,24 +1193,10 @@ public:
}
case WID_BRAS_SHOW_NEWST_TYPE: {
size->width = 0;
if (!_railstation.newstations) {
size->width = 0;
size->height = 0;
break;
}
/* If newstations exist, compute the non-zero minimal size. */
Dimension d = {0, 0};
StringID str = this->GetWidget<NWidgetCore>(widget)->widget_data;
for (auto station_class : this->station_classes) {
StationClass *stclass = StationClass::Get(station_class);
for (uint j = 0; j < stclass->GetSpecCount(); j++) {
const StationSpec *statspec = stclass->GetSpec(j);
SetDParam(0, (statspec != nullptr && statspec->name != 0) ? statspec->name : STR_STATION_CLASS_DFLT_STATION);
d = maxdim(d, GetStringBoundingBox(str));
}
}
size->width = std::max(size->width, d.width + padding.width);
break;
}
@@ -1236,6 +1218,16 @@ public:
}
}
/**
* Get name of custom station.
* @param statspec Custom station to get name of.
* @returns Name of station, or default string if not a custom station.
*/
static StringID GetStationNameString(const StationSpec *statspec)
{
return (statspec != nullptr && statspec->name != STR_NULL) ? statspec->name : STR_STATION_CLASS_DFLT_STATION;
}
void DrawWidget(const Rect &r, WidgetID widget) const override
{
DrawPixelInfo tmp_dpi;
@@ -1284,6 +1276,10 @@ public:
break;
}
case WID_BRAS_SHOW_NEWST_TYPE:
DrawStringMultiLine(r, GetStationNameString(StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type)), TC_ORANGE, SA_CENTER);
break;
case WID_BRAS_IMAGE: {
uint16_t type = this->GetWidget<NWidgetBase>(widget)->GetParentWidget<NWidgetMatrix>()->GetCurrentElement();
assert(type < _railstation.station_count);
@@ -1308,18 +1304,35 @@ public:
}
}
/**
* Get dimensions in pixels of station type names for the given width.
* @param width Width of text in pixels.
* @returns Dimensions required for station type name.
*/
Dimension GetStationTypeNameDimension(int width) const
{
int y = 0;
for (StationClassID cls_id = STAT_CLASS_BEGIN; cls_id < StationClass::GetClassCount(); cls_id++) {
if (cls_id == STAT_CLASS_WAYP) continue;
const StationClass *stclass = StationClass::Get(cls_id);
for (uint j = 0; j < stclass->GetSpecCount(); j++) {
y = std::max(y, GetStringHeight(GetStationNameString(stclass->GetSpec(j)), width));
}
}
return Dimension(width, y);
}
void OnResize() override
{
if (this->vscroll != nullptr) { // New stations available.
this->vscroll->SetCapacityFromWidget(this, WID_BRAS_NEWST_LIST);
}
}
void SetStringParameters(WidgetID widget) const override
{
if (widget == WID_BRAS_SHOW_NEWST_TYPE) {
const StationSpec *statspec = StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type);
SetDParam(0, (statspec != nullptr && statspec->name != 0) ? statspec->name : STR_STATION_CLASS_DFLT_STATION);
if (_railstation.newstations) {
/* Update height of text for station type name widget if its width has changed. */
auto wid = this->GetWidget<NWidgetResizeBase>(WID_BRAS_SHOW_NEWST_TYPE);
if (this->name.width != wid->current_x) this->name = this->GetStationTypeNameDimension(wid->current_x);
if (wid->UpdateVerticalSize(this->name.height)) this->ReInit(0, 0);
}
}
@@ -1561,7 +1574,7 @@ static const NWidgetPart _nested_station_builder_widgets[] = {
NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAS_PLATFORM_DIR_X), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAS_PLATFORM_DIR_Y), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(),
EndContainer(),
NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BRAS_SHOW_NEWST_TYPE), SetMinimalSize(144, 11), SetDataTip(STR_JUST_STRING, STR_NULL), SetTextStyle(TC_ORANGE),
NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_BRAS_SHOW_NEWST_TYPE),
NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_NUMBER_OF_TRACKS, STR_NULL),
NWidget(NWID_HORIZONTAL), SetPIPRatio(1, 0, 1),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),

View File

@@ -1101,6 +1101,8 @@ private:
RoadStopType roadStopType; ///< The RoadStopType for this Window.
uint line_height; ///< Height of a single line in the newstation selection matrix.
uint coverage_height; ///< Height of the coverage texts.
Dimension name; ///< Dimension of roadstop type name widget.
bool newstops; ///< Set if NewGRF roadstops are available.
Scrollbar *vscrollList; ///< Vertical scrollbar of the new station list.
Scrollbar *vscrollMatrix; ///< Vertical scrollbar of the station picker matrix.
@@ -1147,19 +1149,19 @@ public:
this->vscrollList = nullptr;
this->vscrollMatrix = nullptr;
this->roadStopType = rs;
bool newstops = GetIfNewStopsByType(rs, _cur_roadtype);
this->newstops = GetIfNewStopsByType(rs, _cur_roadtype);
this->CreateNestedTree();
/* Hide the station class filter if no stations other than the default one are available. */
this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_DEFSIZE)->SetDisplayedPlane(newstops ? 0 : SZSP_NONE);
this->GetWidget<NWidgetStacked>(WID_BROS_FILTER_CONTAINER)->SetDisplayedPlane(newstops ? 0 : SZSP_HORIZONTAL);
this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_ADDITIONS)->SetDisplayedPlane(newstops ? 0 : SZSP_HORIZONTAL);
this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_ORIENTATION)->SetDisplayedPlane(newstops ? 0 : SZSP_HORIZONTAL);
this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_TYPE_SEL)->SetDisplayedPlane(newstops ? 0 : SZSP_HORIZONTAL);
this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_MATRIX)->SetDisplayedPlane(newstops ? 0 : SZSP_NONE);
this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_RESIZE)->SetDisplayedPlane(newstops ? 0 : SZSP_NONE);
if (newstops) {
this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_DEFSIZE)->SetDisplayedPlane(this->newstops ? 0 : SZSP_NONE);
this->GetWidget<NWidgetStacked>(WID_BROS_FILTER_CONTAINER)->SetDisplayedPlane(this->newstops ? 0 : SZSP_HORIZONTAL);
this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_ADDITIONS)->SetDisplayedPlane(this->newstops ? 0 : SZSP_HORIZONTAL);
this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_ORIENTATION)->SetDisplayedPlane(this->newstops ? 0 : SZSP_HORIZONTAL);
this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_TYPE_SEL)->SetDisplayedPlane(this->newstops ? 0 : SZSP_HORIZONTAL);
this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_MATRIX)->SetDisplayedPlane(this->newstops ? 0 : SZSP_NONE);
this->GetWidget<NWidgetStacked>(WID_BROS_SHOW_NEWST_RESIZE)->SetDisplayedPlane(this->newstops ? 0 : SZSP_NONE);
if (this->newstops) {
this->vscrollList = this->GetScrollbar(WID_BROS_NEWST_SCROLL);
this->vscrollMatrix = this->GetScrollbar(WID_BROS_MATRIX_SCROLL);
@@ -1190,13 +1192,13 @@ public:
this->FinishInitNested(TRANSPORT_ROAD);
this->window_class = (rs == ROADSTOP_BUS) ? WC_BUS_STATION : WC_TRUCK_STATION;
if (!newstops || _roadstop_gui_settings.roadstop_class >= (int)RoadStopClass::GetClassCount()) {
if (!this->newstops || _roadstop_gui_settings.roadstop_class >= (int)RoadStopClass::GetClassCount()) {
/* There's no new stops available or the list has reduced in size.
* Now, set the default road stops as selected. */
_roadstop_gui_settings.roadstop_class = ROADSTOP_CLASS_DFLT;
_roadstop_gui_settings.roadstop_type = 0;
}
if (newstops) {
if (this->newstops) {
/* The currently selected class doesn't have any stops for this RoadStopType, reset the selection. */
if (!GetIfClassHasNewStopsByType(RoadStopClass::Get(_roadstop_gui_settings.roadstop_class), rs, _cur_roadtype)) {
_roadstop_gui_settings.roadstop_class = ROADSTOP_CLASS_DFLT;
@@ -1347,31 +1349,15 @@ public:
{
switch (widget) {
case WID_BROS_NEWST_LIST: {
Dimension d = { 0, 0 };
for (auto rs_class : this->roadstop_classes) {
d = maxdim(d, GetStringBoundingBox(RoadStopClass::Get(rs_class)->name));
}
size->width = std::max(size->width, d.width + padding.width);
this->line_height = GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.matrix.Vertical();
this->line_height = GetCharacterHeight(FS_NORMAL) + padding.height;
size->height = 5 * this->line_height;
resize->height = this->line_height;
break;
}
case WID_BROS_SHOW_NEWST_TYPE: {
Dimension d = {0, 0};
StringID str = this->GetWidget<NWidgetCore>(widget)->widget_data;
for (auto roadstop_class : this->roadstop_classes) {
RoadStopClass *rs_class = RoadStopClass::Get(roadstop_class);
for (uint j = 0; j < rs_class->GetSpecCount(); j++) {
const RoadStopSpec *roadstopspec = rs_class->GetSpec(j);
SetDParam(0, (roadstopspec != nullptr && roadstopspec->name != 0) ? roadstopspec->name : STR_STATION_CLASS_DFLT_ROADSTOP);
d = maxdim(d, GetStringBoundingBox(str));
}
}
size->width = std::max(size->width, d.width + padding.width);
case WID_BROS_SHOW_NEWST_TYPE:
size->width = 0;
break;
}
case WID_BROS_STATION_NE:
case WID_BROS_STATION_SE:
@@ -1407,6 +1393,16 @@ public:
}
}
/**
* Get name of custom road stop.
* @param roadstopspec Custom road stop to get name of.
* @returns Name of road stop, or default string if not a custom road stop.
*/
static StringID GetRoadStopNameString(const RoadStopSpec *roadstopspec)
{
return (roadstopspec != nullptr && roadstopspec->name != 0) ? roadstopspec->name : STR_STATION_CLASS_DFLT_ROADSTOP;
}
void DrawWidget(const Rect &r, WidgetID widget) const override
{
switch (widget) {
@@ -1450,6 +1446,10 @@ public:
break;
}
case WID_BROS_SHOW_NEWST_TYPE:
DrawStringMultiLine(r, GetRoadStopNameString(RoadStopClass::Get(_roadstop_gui_settings.roadstop_class)->GetSpec(_roadstop_gui_settings.roadstop_type)), TC_ORANGE, SA_CENTER);
break;
case WID_BROS_IMAGE: {
uint16_t type = this->GetWidget<NWidgetBase>(widget)->GetParentWidget<NWidgetMatrix>()->GetCurrentElement();
assert(type < _roadstop_gui_settings.roadstop_count);
@@ -1480,18 +1480,35 @@ public:
}
}
/**
* Get dimensions in pixels of roadstop type names for the given width.
* @param width Width of text in pixels.
* @returns Dimensions required for roadstop type name.
*/
Dimension GetRoadStopTypeNameDimension(int width) const
{
int y = 0;
for (RoadStopClassID cls_id = ROADSTOP_CLASS_BEGIN; cls_id < RoadStopClass::GetClassCount(); cls_id++) {
if (cls_id == ROADSTOP_CLASS_WAYP) continue;
RoadStopClass *rs_class = RoadStopClass::Get(cls_id);
for (uint j = 0; j < rs_class->GetSpecCount(); j++) {
y = std::max(y, GetStringHeight(GetRoadStopNameString(rs_class->GetSpec(j)), width));
}
}
return Dimension(width, y);
}
void OnResize() override
{
if (this->vscrollList != nullptr) {
this->vscrollList->SetCapacityFromWidget(this, WID_BROS_NEWST_LIST);
}
}
void SetStringParameters(WidgetID widget) const override
{
if (widget == WID_BROS_SHOW_NEWST_TYPE) {
const RoadStopSpec *roadstopspec = RoadStopClass::Get(_roadstop_gui_settings.roadstop_class)->GetSpec(_roadstop_gui_settings.roadstop_type);
SetDParam(0, (roadstopspec != nullptr && roadstopspec->name != 0) ? roadstopspec->name : STR_STATION_CLASS_DFLT_ROADSTOP);
if (this->newstops) {
/* Update height of text for roadtype type name widget if its width has changed. */
NWidgetResizeBase *wid = this->GetWidget<NWidgetResizeBase>(WID_BROS_SHOW_NEWST_TYPE);
if (this->name.width != wid->current_x) this->name = this->GetRoadStopTypeNameDimension(wid->current_x);
if (wid->UpdateVerticalSize(this->name.height)) this->ReInit(0, 0);
}
}
@@ -1647,7 +1664,7 @@ static const NWidgetPart _nested_road_station_picker_widgets[] = {
EndContainer(),
EndContainer(),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_TYPE_SEL),
NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_SHOW_NEWST_TYPE), SetMinimalSize(144, 8), SetDataTip(STR_JUST_STRING, STR_NULL), SetTextStyle(TC_ORANGE), SetFill(1, 0),
NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_BROS_SHOW_NEWST_TYPE),
EndContainer(),
NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetFill(1, 0),
NWidget(NWID_HORIZONTAL), SetPIPRatio(1, 0, 1),
@@ -1724,7 +1741,7 @@ static const NWidgetPart _nested_tram_station_picker_widgets[] = {
NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetMinimalSize(66, 50), SetFill(0, 0), EndContainer(),
EndContainer(),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BROS_SHOW_NEWST_TYPE_SEL),
NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_SHOW_NEWST_TYPE), SetMinimalSize(144, 8), SetDataTip(STR_JUST_STRING, STR_NULL), SetTextStyle(TC_ORANGE), SetFill(1, 0),
NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_BROS_SHOW_NEWST_TYPE),
EndContainer(),
NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetFill(1, 0),
NWidget(NWID_HORIZONTAL), SetPIPRatio(1, 0, 1),