summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/widgets/dropdown.cpp74
-rw-r--r--src/widgets/dropdown_type.h1
2 files changed, 52 insertions, 23 deletions
diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp
index 61179365b..90b57730f 100644
--- a/src/widgets/dropdown.cpp
+++ b/src/widgets/dropdown.cpp
@@ -20,6 +20,11 @@ StringID DropDownListItem::String() const
return STR_NULL;
}
+uint DropDownListItem::Height(uint width) const
+{
+ return 10;
+}
+
StringID DropDownListStringItem::String() const
{
return this->string;
@@ -66,20 +71,25 @@ static int GetDropDownItem(const Window *w)
{
if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) < 0) return -1;
- int y = _cursor.pos.y - w->top - 2 + w->vscroll.pos * 10;
- if (y < 0) return -1;
+ int y = _cursor.pos.y - w->top - 2;
+ int width = w->widget[0].right - 3;
+ int pos = w->vscroll.pos;
- uint selected_row = y / 10;
const DropDownList *list = WP(w, dropdown_d).list;
- if (selected_row >= list->size()) return -1;
+ for (DropDownList::const_iterator it = list->begin(); it != list->end(); ++it) {
+ /* Skip items that are scrolled up */
+ if (--pos >= 0) continue;
- for (DropDownList::const_iterator it = list->begin(); it != list->end(); ++it, selected_row--) {
- if (selected_row == 0) {
- const DropDownListItem *item = *it;
+ const DropDownListItem *item = *it;
+ int item_height = item->Height(width);
+
+ if (y < item_height) {
if (item->masked || item->String() == STR_NULL) return -1;
return item->result;
}
+
+ y -= item_height;
}
return -1;
@@ -92,24 +102,30 @@ static void DropDownMenuWndProc(Window *w, WindowEvent *e)
DrawWindowWidgets(w);
int x = 1;
- int y = 2 - w->vscroll.pos * 10;
+ int y = 2;
int sel = WP(w, dropdown_d).selected_index;
int width = w->widget[0].right - 3;
- int height = w->widget[0].bottom - 3;
+ int height = w->widget[0].bottom;
+ int pos = w->vscroll.pos;
DropDownList *list = WP(w, dropdown_d).list;
for (DropDownList::const_iterator it = list->begin(); it != list->end(); ++it) {
- if (y >= 0 && y <= height) {
- const DropDownListItem *item = *it;
+ const DropDownListItem *item = *it;
+ int item_height = item->Height(width);
+
+ /* Skip items that are scrolled up */
+ if (--pos >= 0) continue;
+
+ if (y + item_height < height) {
if (item->String() != STR_NULL) {
- if (sel == item->result) GfxFillRect(x + 1, y, x + width, y + 9, 0);
+ if (sel == item->result) GfxFillRect(x + 1, y, x + width, y + item_height - 1, 0);
DrawStringTruncated(x + 2, y, item->String(), sel == item->result ? TC_WHITE : TC_BLACK, x + width);
if (item->masked) {
- GfxFillRect(x, y, x + width, y + 9,
+ GfxFillRect(x, y, x + width, y + item_height - 1,
(1 << PALETTE_MODIFIER_GREYOUT) | _colour_gradient[w->widget[0].color][5]
);
}
@@ -121,7 +137,7 @@ static void DropDownMenuWndProc(Window *w, WindowEvent *e)
GfxFillRect(x + 1, y + 4, x + w->width - 5, y + 4, c2);
}
}
- y += 10;
+ y += item_height;
}
} break;
@@ -221,7 +237,17 @@ void ShowDropDownList(Window *w, DropDownList *list, int selected, int button, u
/* The preferred position is just below the dropdown calling widget */
int top = w->top + wi->bottom + 1;
- int height = list->size() * 10 + 4;
+
+ /* Total length of list */
+ int list_height = 0;
+
+ for (DropDownList::const_iterator it = list->begin(); it != list->end(); ++it) {
+ DropDownListItem *item = *it;
+ list_height += item->Height(width);
+ }
+
+ /* Height of window visible */
+ int height = list_height;
/* Check if the status bar is visible, as we don't want to draw over it */
Window *w3 = FindWindowById(WC_STATUS_BAR, 0);
@@ -230,18 +256,19 @@ void ShowDropDownList(Window *w, DropDownList *list, int selected, int button, u
bool scroll = false;
/* Check if the dropdown will fully fit below the widget */
- if (top + height >= screen_bottom) {
+ if (top + height + 4 >= screen_bottom) {
w3 = FindWindowById(WC_MAIN_TOOLBAR, 0);
int screen_top = w3 == NULL ? 0 : w3->top + w3->height;
/* If not, check if it will fit above the widget */
if (w->top + wi->top - height > screen_top) {
- top = w->top + wi->top - height;
+ top = w->top + wi->top - height - 4;
} else {
/* ... and lastly if it won't, enable the scroll bar and fit the
* list in below the widget */
- int rows = (screen_bottom - 4 - top) / 10;
- height = rows * 10 + 4;
+ int avg_height = list_height / list->size();
+ int rows = (screen_bottom - 4 - top) / avg_height;
+ height = rows * avg_height;
scroll = true;
}
}
@@ -252,14 +279,14 @@ void ShowDropDownList(Window *w, DropDownList *list, int selected, int button, u
w->left + wi->left,
top,
width,
- height,
+ height + 4,
DropDownMenuWndProc,
WC_DROPDOWN_MENU,
_dropdown_menu_widgets);
dw->widget[0].color = wi->color;
dw->widget[0].right = width - 1;
- dw->widget[0].bottom = height - 1;
+ dw->widget[0].bottom = height + 3;
dw->SetWidgetHiddenState(1, !scroll);
@@ -269,10 +296,11 @@ void ShowDropDownList(Window *w, DropDownList *list, int selected, int button, u
dw->widget[1].color = wi->color;
dw->widget[1].right = dw->widget[0].right;
dw->widget[1].left = dw->widget[1].right - 11;
- dw->widget[1].bottom = height - 1;
+ dw->widget[1].bottom = dw->widget[0].bottom;
dw->widget[0].right -= 12;
- dw->vscroll.cap = (height - 4) / 10;
+ /* Capacity is the average number of items visible */
+ dw->vscroll.cap = height * list->size() / list_height;
dw->vscroll.count = list->size();
}
diff --git a/src/widgets/dropdown_type.h b/src/widgets/dropdown_type.h
index 29a40962c..859b331d2 100644
--- a/src/widgets/dropdown_type.h
+++ b/src/widgets/dropdown_type.h
@@ -18,6 +18,7 @@ public:
DropDownListItem(int result, bool masked) : result(result), masked(masked) {}
virtual ~DropDownListItem() {}
virtual StringID String() const;
+ virtual uint Height(uint width) const;
};
/**