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 e837727..5d05b20 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -356,33 +356,56 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b 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 */ + /* Is it better to put the dropdown above the widget? */ + bool above = false; + + /* Available height below (or above, if it is + * a better place to put the dropdown). */ + int available_height = GetMainViewBottom() - top - 4; + + /* If the dropdown doesn't fully fit below the widget... */ + if (height >= available_height) { + + 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 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. */ + + /* Add space for the scrollbar. */ 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); Point dw_pos = { w->left + (_current_text_dir == TD_RTL ? wi_rect.right + 1 - width : wi_rect.left), top}; Dimension dw_size = {width, height}; - new DropdownWindow(w, list, selected, button, instant_close, dw_pos, dw_size, wi_colour, scroll); + DropdownWindow *dropdown = new DropdownWindow(w, list, selected, button, instant_close, dw_pos, dw_size, wi_colour, scroll); + + /* The dropdown starts scrolling downwards when opening it towards + * the top and holding down the mouse button. It can be fooled by + * opening the dropdown scrolled to the very bottom. */ + if (above && scroll) dropdown->vscroll->UpdatePosition(INT_MAX); } /**