mirror of https://github.com/OpenTTD/OpenTTD
(svn r7086) -Featurette: Add additional positioning for long dropdown lists: first, try to fit the dropdown below the calling widget, as before; second, try to fit it wholly above the calling widget; and lastly, fit the list below the widget and add a scrollbar.
parent
35e53249ed
commit
ca8605ebc5
80
widget.c
80
widget.c
|
@ -474,6 +474,7 @@ draw_default:;
|
||||||
|
|
||||||
static const Widget _dropdown_menu_widgets[] = {
|
static const Widget _dropdown_menu_widgets[] = {
|
||||||
{ WWT_PANEL, RESIZE_NONE, 0, 0, 0, 0, 0, 0x0, STR_NULL},
|
{ WWT_PANEL, RESIZE_NONE, 0, 0, 0, 0, 0, 0x0, STR_NULL},
|
||||||
|
{ WWT_SCROLLBAR, RESIZE_NONE, 0, 0, 0, 0, 0, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
|
||||||
{ WIDGETS_END},
|
{ WIDGETS_END},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -485,7 +486,7 @@ static int GetDropdownItem(const Window *w)
|
||||||
if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) < 0)
|
if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
y = _cursor.pos.y - w->top - 2;
|
y = _cursor.pos.y - w->top - 2 + w->vscroll.pos;
|
||||||
|
|
||||||
if (y < 0)
|
if (y < 0)
|
||||||
return - 1;
|
return - 1;
|
||||||
|
@ -508,12 +509,28 @@ static void DropdownMenuWndProc(Window *w, WindowEvent *e)
|
||||||
switch (e->event) {
|
switch (e->event) {
|
||||||
case WE_PAINT: {
|
case WE_PAINT: {
|
||||||
int x,y,i,sel;
|
int x,y,i,sel;
|
||||||
|
int width;
|
||||||
|
bool scroll = w->vscroll.count > 0;
|
||||||
|
DrawPixelInfo tmp_dpi, *old_dpi = NULL;
|
||||||
|
|
||||||
DrawWindowWidgets(w);
|
DrawWindowWidgets(w);
|
||||||
|
|
||||||
x = 1;
|
x = 1;
|
||||||
y = 2;
|
y = 2 - w->vscroll.pos;
|
||||||
|
|
||||||
|
if (scroll) {
|
||||||
|
/* Set up the bounding box for drawing the list content */
|
||||||
|
if (!FillDrawPixelInfo(&tmp_dpi, w->widget[0].left + 1, w->widget[0].top + 1, w->widget[0].right - 1, w->widget[0].bottom - 1)) return;
|
||||||
|
old_dpi = _cur_dpi;
|
||||||
|
_cur_dpi = &tmp_dpi;
|
||||||
|
|
||||||
|
/* Adjust x and y for the 1 pixel offset of the bounding box */
|
||||||
|
x--;
|
||||||
|
y--;
|
||||||
|
}
|
||||||
|
|
||||||
sel = WP(w,dropdown_d).selected_index;
|
sel = WP(w,dropdown_d).selected_index;
|
||||||
|
width = w->widget[0].right - 3;
|
||||||
|
|
||||||
for (i = 0; WP(w,dropdown_d).items[i] != INVALID_STRING_ID; i++) {
|
for (i = 0; WP(w,dropdown_d).items[i] != INVALID_STRING_ID; i++) {
|
||||||
if (HASBIT(WP(w,dropdown_d).hidden_state, i)) {
|
if (HASBIT(WP(w,dropdown_d).hidden_state, i)) {
|
||||||
|
@ -521,11 +538,11 @@ static void DropdownMenuWndProc(Window *w, WindowEvent *e)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (WP(w,dropdown_d).items[i] != STR_NULL) {
|
if (WP(w,dropdown_d).items[i] != STR_NULL) {
|
||||||
if (sel == 0) GfxFillRect(x + 1, y, x + w->width - 4, y + 9, 0);
|
if (sel == 0) GfxFillRect(x + 1, y, x + width, y + 9, 0);
|
||||||
DrawStringTruncated(x + 2, y, WP(w,dropdown_d).items[i], sel == 0 ? 12 : 16, w->width - 4);
|
DrawStringTruncated(x + 2, y, WP(w,dropdown_d).items[i], sel == 0 ? 12 : 16, x + width);
|
||||||
|
|
||||||
if (HASBIT(WP(w,dropdown_d).disabled_state, i)) {
|
if (HASBIT(WP(w,dropdown_d).disabled_state, i)) {
|
||||||
GfxFillRect(x, y, x + w->width - 3, y + 9,
|
GfxFillRect(x, y, x + width, y + 9,
|
||||||
PALETTE_MODIFIER_GREYOUT | _colour_gradient[_dropdown_menu_widgets[0].color][5]
|
PALETTE_MODIFIER_GREYOUT | _colour_gradient[_dropdown_menu_widgets[0].color][5]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -539,9 +556,13 @@ static void DropdownMenuWndProc(Window *w, WindowEvent *e)
|
||||||
y += 10;
|
y += 10;
|
||||||
sel--;
|
sel--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reset the bounding box if we had set it up */
|
||||||
|
if (scroll) _cur_dpi = old_dpi;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case WE_CLICK: {
|
case WE_CLICK: {
|
||||||
|
if (e->we.click.widget != 0) break;
|
||||||
item = GetDropdownItem(w);
|
item = GetDropdownItem(w);
|
||||||
if (item >= 0) {
|
if (item >= 0) {
|
||||||
WP(w,dropdown_d).click_delay = 4;
|
WP(w,dropdown_d).click_delay = 4;
|
||||||
|
@ -600,7 +621,11 @@ void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int butt
|
||||||
int i;
|
int i;
|
||||||
const Widget *wi;
|
const Widget *wi;
|
||||||
Window *w2;
|
Window *w2;
|
||||||
|
const Window *w3;
|
||||||
bool is_dropdown_menu_shown = IsWindowWidgetLowered(w, button);
|
bool is_dropdown_menu_shown = IsWindowWidgetLowered(w, button);
|
||||||
|
int top, height;
|
||||||
|
int screen_top, screen_bottom;
|
||||||
|
bool scroll = false;
|
||||||
|
|
||||||
cls = w->window_class;
|
cls = w->window_class;
|
||||||
num = w->window_number;
|
num = w->window_number;
|
||||||
|
@ -626,19 +651,58 @@ void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int butt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The preferred position is just below the dropdown calling widget */
|
||||||
|
top = w->top + wi->bottom + 2;
|
||||||
|
height = i * 10 + 4;
|
||||||
|
|
||||||
|
w3 = FindWindowById(WC_STATUS_BAR, 0);
|
||||||
|
screen_bottom = w3 == NULL ? _screen.height : w3->top;
|
||||||
|
|
||||||
|
/* Check if the dropdown will fully fit below the widget */
|
||||||
|
if (top + height >= screen_bottom) {
|
||||||
|
w3 = FindWindowById(WC_MAIN_TOOLBAR, 0);
|
||||||
|
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 - 1 > screen_top) {
|
||||||
|
top = w->top + wi->top - height - 1;
|
||||||
|
} else {
|
||||||
|
/* ... and lastly if it won't, enable the scroll bar and fit the
|
||||||
|
* list in below the widget */
|
||||||
|
height = screen_bottom - top;
|
||||||
|
scroll = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
w2 = AllocateWindow(
|
w2 = AllocateWindow(
|
||||||
w->left + wi[-1].left + 1,
|
w->left + wi[-1].left + 1,
|
||||||
w->top + wi->bottom + 2,
|
top,
|
||||||
wi->right - wi[-1].left + 1,
|
wi->right - wi[-1].left + 1,
|
||||||
i * 10 + 4,
|
height,
|
||||||
DropdownMenuWndProc,
|
DropdownMenuWndProc,
|
||||||
WC_DROPDOWN_MENU,
|
WC_DROPDOWN_MENU,
|
||||||
_dropdown_menu_widgets);
|
_dropdown_menu_widgets);
|
||||||
|
|
||||||
w2->widget[0].color = wi->color;
|
w2->widget[0].color = wi->color;
|
||||||
w2->widget[0].right = wi->right - wi[-1].left;
|
w2->widget[0].right = wi->right - wi[-1].left;
|
||||||
w2->widget[0].bottom = i * 10 + 3;
|
w2->widget[0].bottom = height - 1;
|
||||||
|
|
||||||
|
SetWindowWidgetHiddenState(w2, 1, !scroll);
|
||||||
|
|
||||||
|
if (scroll) {
|
||||||
|
/* We're scrolling, so enable the scroll bar and shrink the list by
|
||||||
|
* the scrollbar's width */
|
||||||
|
w2->widget[1].color = wi->color;
|
||||||
|
w2->widget[1].right = w2->widget[0].right;
|
||||||
|
w2->widget[1].left = w2->widget[1].right - 11;
|
||||||
|
w2->widget[1].bottom = height - 1;
|
||||||
|
w2->widget[0].right -= 12;
|
||||||
|
|
||||||
|
w2->vscroll.cap = height - 1;
|
||||||
|
w2->vscroll.count = i * 10 + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
w2->desc_flags = WDF_DEF_WIDGET;
|
||||||
w2->flags4 &= ~WF_WHITE_BORDER_MASK;
|
w2->flags4 &= ~WF_WHITE_BORDER_MASK;
|
||||||
|
|
||||||
WP(w2,dropdown_d).disabled_state = disabled_mask;
|
WP(w2,dropdown_d).disabled_state = disabled_mask;
|
||||||
|
|
Loading…
Reference in New Issue