(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.
authorpeter1138
Mon, 06 Nov 2006 22:06:29 +0000
changeset 5041 674e5e1b4ad4
parent 5040 ff048be5d100
child 5042 1cac491bee1a
(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.
widget.c
--- a/widget.c	Mon Nov 06 21:13:18 2006 +0000
+++ b/widget.c	Mon Nov 06 22:06:29 2006 +0000
@@ -474,6 +474,7 @@
 
 static const Widget _dropdown_menu_widgets[] = {
 {      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},
 };
 
@@ -485,7 +486,7 @@
 	if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) < 0)
 		return -1;
 
-	y = _cursor.pos.y - w->top - 2;
+	y = _cursor.pos.y - w->top - 2 + w->vscroll.pos;
 
 	if (y < 0)
 		return - 1;
@@ -508,12 +509,28 @@
 	switch (e->event) {
 		case WE_PAINT: {
 			int x,y,i,sel;
+			int width;
+			bool scroll = w->vscroll.count > 0;
+			DrawPixelInfo tmp_dpi, *old_dpi = NULL;
 
 			DrawWindowWidgets(w);
 
 			x = 1;
-			y = 2;
-			sel    = WP(w,dropdown_d).selected_index;
+			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;
+			width = w->widget[0].right - 3;
 
 			for (i = 0; WP(w,dropdown_d).items[i] != INVALID_STRING_ID; i++) {
 				if (HASBIT(WP(w,dropdown_d).hidden_state, i)) {
@@ -521,11 +538,11 @@
 					continue;
 				}
 				if (WP(w,dropdown_d).items[i] != STR_NULL) {
-					if (sel == 0) GfxFillRect(x + 1, y, x + w->width - 4, y + 9, 0);
-					DrawStringTruncated(x + 2, y, WP(w,dropdown_d).items[i], sel == 0 ? 12 : 16, w->width - 4);
+					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, x + width);
 
 					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]
 						);
 					}
@@ -539,9 +556,13 @@
 				y += 10;
 				sel--;
 			}
+
+			/* Reset the bounding box if we had set it up */
+			if (scroll) _cur_dpi = old_dpi;
 		} break;
 
 		case WE_CLICK: {
+			if (e->we.click.widget != 0) break;
 			item = GetDropdownItem(w);
 			if (item >= 0) {
 				WP(w,dropdown_d).click_delay = 4;
@@ -600,7 +621,11 @@
 	int i;
 	const Widget *wi;
 	Window *w2;
+	const Window *w3;
 	bool is_dropdown_menu_shown = IsWindowWidgetLowered(w, button);
+	int top, height;
+	int screen_top, screen_bottom;
+	bool scroll = false;
 
 	cls = w->window_class;
 	num = w->window_number;
@@ -626,19 +651,58 @@
 		}
 	}
 
+	/* 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(
 		w->left + wi[-1].left + 1,
-		w->top + wi->bottom + 2,
+		top,
 		wi->right - wi[-1].left + 1,
-		i * 10 + 4,
+		height,
 		DropdownMenuWndProc,
 		WC_DROPDOWN_MENU,
 		_dropdown_menu_widgets);
 
 	w2->widget[0].color = wi->color;
 	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;
 
 	WP(w2,dropdown_d).disabled_state = disabled_mask;