Allow drawing dropdowns with scrollbars above the widgets. Also add an assert when no single item of a dropdown can be drawn. diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 0ff6ab5..bf0ea85 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -344,44 +344,56 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b /* The preferred width equals the calling widget */ uint width = wi_rect.right - wi_rect.left + 1; + /* Longest item in the list, if auto_width is enabled */ uint max_item_width = 0; - if (auto_width) { - /* Find the longest item in the list */ - for (const DropDownListItem * const *it = list->Begin(); it != list->End(); ++it) { - const DropDownListItem *item = *it; - max_item_width = max(max_item_width, item->Width() + 5); - } - } - /* Total length of list */ int height = 0; for (const DropDownListItem * const *it = list->Begin(); it != list->End(); ++it) { const DropDownListItem *item = *it; height += item->Height(width); + if (auto_width) max_item_width = max(max_item_width, item->Width() + 5); } - /* Check if the status bar is visible, as we don't want to draw over it */ - int screen_bottom = GetMainViewBottom(); + /* Is a scrollbar necessary? */ bool scroll = false; - /* Check if the dropdown will fully fit below the widget */ - if (top + height + 4 >= screen_bottom) { - /* If not, check if it will fit above the widget */ - if (w->top + wi_rect.top - height > GetMainViewTop()) { - top = w->top + wi_rect.top - height - 4; - } else { - /* ... and lastly if it won't, enable the scroll bar and fit the - * list in below the widget */ + /* Available height below (or above, if the dropdown will + * be drawn above the widget). */ + int available_height = GetMainViewBottom() - top - 4; + + /* If the dropdown doesn't fully fit below the widget... */ + if (height >= available_height) { + /* Is it better to put the dropdown above the widget? */ + bool above = false; + + /* Space available above the widget. */ + int available_height_above = w->top + wi_rect.top - GetMainViewTop() - 4; + + /* Put the dropdown where there is more available space. */ + if (available_height_above > available_height) { + above = true; + available_height = available_height_above; + } + + /* If the dropdown still doesn't fully fit, we need a dropdown. */ + if (height >= available_height) { + scroll = true; int avg_height = height / (int)list->Length(); - int rows = (screen_bottom - 4 - top) / avg_height; + + /* Check at least there is space for one item. */ + assert(available_height >= avg_height); + + /* Fit the list. */ + int rows = available_height / avg_height; height = rows * avg_height; - scroll = true; - /* Add space for the scroll bar if we automatically determined - * the width of the list. */ - max_item_width += NWidgetScrollbar::GetVerticalDimension().width; + + /* Add space for the scrollbar. */ + if (auto_width) max_item_width += NWidgetScrollbar::GetVerticalDimension().width; } + + if (above) top = w->top + wi_rect.top - height - 4; } if (auto_width) width = max(width, max_item_width);