/**
 * Show a drop down list.
 * @param w        Parent window for the list.
 * @param list     Prepopulated DropDownList. Will be deleted when the list is
 *                 closed.
 * @param selected The initially selected list item.
 * @param button   The widget which is passed to Window::OnDropdownSelect and OnDropdownClose.
 *                 Unless you override those functions, this should be then widget index of the dropdown button.
 * @param wi_rect  Coord of the parent drop down button, used to position the dropdown menu.
 * @param auto_width The width is determined by the widest item in the list,
 *                   in this case only one of \a left or \a right is used (depending on text direction).
 * @param instant_close Set to true if releasing mouse button should close the
 *                      list regardless of where the cursor is.
 */
void ShowDropDownListAt(Window *w, DropDownList *list, int selected, int button, Rect wi_rect, Colours wi_colour, bool auto_width, bool instant_close)
{
	DeleteWindowById(WC_DROPDOWN_MENU, 0);

	/* The preferred position is just below the dropdown calling widget */
	int top = w->top + wi_rect.bottom + 1;

	/* The preferred width equals the calling widget */
	uint width = wi_rect.right - wi_rect.left + 1;

	uint max_item_width = 0;

	if (auto_width) {
		/* Find the longest item in the list */
		for (DropDownList::const_iterator 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 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 */
	int screen_bottom = GetMainViewBottom();
	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 */
			int avg_height = list_height / (int)list->size();
			int rows = (screen_bottom - 4 - top) / 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;
		}
	}

	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);
}
Example #2
0
			}
		}
	}

	virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number)
	{
		/* Position (0, 0) given, center the window. */
		if (this->position.x == 0 && this->position.y == 0) {
			Point pt = {(_screen.width - sm_width) >> 1, (_screen.height - sm_height) >> 1};
			return pt;
		}

		/* Find the free screen space between the main toolbar at the top, and the statusbar at the bottom.
		 * Add a fixed distance 20 to make it less cluttered.
		 */
		int scr_top = GetMainViewTop() + 20;
		int scr_bot = GetMainViewBottom() - 20;

		Point pt = RemapCoords2(this->position.x, this->position.y);
		const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
		if (this->face == INVALID_COMPANY) {
			/* move x pos to opposite corner */
			pt.x = UnScaleByZoom(pt.x - vp->virtual_left, vp->zoom) + vp->left;
			pt.x = (pt.x < (_screen.width >> 1)) ? _screen.width - sm_width - 20 : 20; // Stay 20 pixels away from the edge of the screen.

			/* move y pos to opposite corner */
			pt.y = UnScaleByZoom(pt.y - vp->virtual_top, vp->zoom) + vp->top;
			pt.y = (pt.y < (_screen.height >> 1)) ? scr_bot - sm_height : scr_top;
		} else {
			pt.x = Clamp(UnScaleByZoom(pt.x - vp->virtual_left, vp->zoom) + vp->left - (sm_width / 2),  0, _screen.width  - sm_width);
			pt.y = Clamp(UnScaleByZoom(pt.y - vp->virtual_top,  vp->zoom) + vp->top  - (sm_height / 2), scr_top, scr_bot - sm_height);
Example #3
0
void ShowDropDownList(Window *w, DropDownList *list, int selected, int button, uint width, bool auto_width, bool instant_close)
{
	DeleteWindowById(WC_DROPDOWN_MENU, 0);

	/* Our parent's button widget is used to determine where to place the drop
	 * down list window. */
	Rect wi_rect;
	Colours wi_colour;
	NWidgetCore *nwi = w->GetWidget<NWidgetCore>(button);
	wi_rect.left   = nwi->pos_x;
	wi_rect.right  = nwi->pos_x + nwi->current_x - 1;
	wi_rect.top    = nwi->pos_y;
	wi_rect.bottom = nwi->pos_y + nwi->current_y - 1;
	wi_colour = nwi->colour;

	if (nwi->type == NWID_BUTTON_DROPDOWN) {
		nwi->disp_flags |= ND_DROPDOWN_ACTIVE;
	} else {
		w->LowerWidget(button);
	}
	w->SetWidgetDirty(button);

	/* The preferred position is just below the dropdown calling widget */
	int top = w->top + wi_rect.bottom + 1;

	if (width == 0) width = wi_rect.right - wi_rect.left + 1;

	uint max_item_width = 0;

	if (auto_width) {
		/* Find the longest item in the list */
		for (DropDownList::const_iterator 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 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 */
	int screen_bottom = GetMainViewBottom();
	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 */
			int avg_height = list_height / (int)list->size();
			int rows = (screen_bottom - 4 - top) / 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 += WD_VSCROLLBAR_WIDTH;
		}
	}

	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);
}
Example #4
0
/**
 * Show a drop down list.
 * @param w        Parent window for the list.
 * @param list     Prepopulated DropDownList. Will be deleted when the list is
 *                 closed.
 * @param selected The initially selected list item.
 * @param button   The widget which is passed to Window::OnDropdownSelect and OnDropdownClose.
 *                 Unless you override those functions, this should be then widget index of the dropdown button.
 * @param wi_rect  Coord of the parent drop down button, used to position the dropdown menu.
 * @param auto_width The width is determined by the widest item in the list,
 *                   in this case only one of \a left or \a right is used (depending on text direction).
 * @param instant_close Set to true if releasing mouse button should close the
 *                      list regardless of where the cursor is.
 */
void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int button, Rect wi_rect, Colours wi_colour, bool auto_width, bool instant_close)
{
	DeleteWindowById(WC_DROPDOWN_MENU, 0);

	/* The preferred position is just below the dropdown calling widget */
	int top = w->top + wi_rect.bottom + 1;

	/* 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;

	/* 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();
	bool scroll = false;

	enum { DISPLAY_BORDER = 20, TOP_BORDER = 4 };

	/* Check if the dropdown will fully fit below the widget */
	if (top + height + DISPLAY_BORDER >= screen_bottom) {
		/* If not, check if it will fit above the widget */
		int screen_top = GetMainViewTop();
		if (w->top + wi_rect.top - TOP_BORDER > screen_top + height) {
			top = w->top + wi_rect.top - height - TOP_BORDER;
		} else {
			/* If it doesn't fit above the widget, we need to enable a scrollbar... */
			int avg_height = height / (int)list->Length();
			scroll = true;

			/* ... and choose whether to put the list above or below the widget. */
			bool put_above = false;
			int available_height = screen_bottom - w->top - wi_rect.bottom;
			if (w->top + wi_rect.top - screen_top > available_height) {
				// Put it above.
				available_height = w->top + wi_rect.top - screen_top - DISPLAY_BORDER - TOP_BORDER;
				put_above = true;
			}

			/* Check at least there is space for one item. */
			assert(available_height >= avg_height);

			/* ... and lastly if it won't, enable the scroll bar and fit the
			 * list in below the widget */
			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;

			/* ... and set the top position if needed. */
			if (put_above) {
				top = w->top + wi_rect.top - height - TOP_BORDER;
			}
		}
	}

	if (auto_width) width = max(width, max_item_width);

	Point dw_pos = { w->left + (_current_text_dir == TD_RTL ? wi_rect.right + 1 - (int)width : wi_rect.left), top};
	Dimension dw_size = {width, (uint)height};
	new DropdownWindow(w, list, selected, button, instant_close, dw_pos, dw_size, wi_colour, scroll);
}
Example #5
0
/**
 * Show a drop down list.
 * @param w        Parent window for the list.
 * @param list     Prepopulated DropDownList. Will be deleted when the list is
 *                 closed.
 * @param selected The initially selected list item.
 * @param button   The widget which is passed to Window::OnDropdownSelect and OnDropdownClose.
 *                 Unless you override those functions, this should be then widget index of the dropdown button.
 * @param wi_rect  Coord of the parent drop down button, used to position the dropdown menu.
 * @param auto_width The width is determined by the widest item in the list,
 *                   in this case only one of \a left or \a right is used (depending on text direction).
 * @param instant_close Set to true if releasing mouse button should close the
 *                      list regardless of where the cursor is.
 */
void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int button, Rect wi_rect, Colours wi_colour, bool auto_width, bool instant_close)
{
	DeleteWindowById(WC_DROPDOWN_MENU, 0);

	/* The preferred position is just below the dropdown calling widget */
	int top = w->top + wi_rect.bottom + 1;

	/* 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;

	/* Total height of list */
	uint 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);
	}

	/* Scrollbar needed? */
	bool scroll = false;

	/* Is it better to place the dropdown above the widget? */
	bool above = false;

	/* Available height below (or above, if the dropdown is placed above the widget). */
	uint available_height = (uint)max(GetMainViewBottom() - top - 4, 0);

	/* If the dropdown doesn't fully fit below the widget... */
	if (height > available_height) {

		uint available_height_above = (uint)max(w->top + wi_rect.top - GetMainViewTop() - 4, 0);

		/* Put the dropdown above if 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;
			uint avg_height = height / list->Length();

			/* Check at least there is space for one item. */
			assert(available_height >= avg_height);

			/* Fit the list. */
			uint rows = available_height / avg_height;
			height = rows * avg_height;

			/* Add space for the scrollbar. */
			max_item_width += NWidgetScrollbar::GetVerticalDimension().width;
		}

		/* Set the top position if needed. */
		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 - (int)width : wi_rect.left), top};
	Dimension dw_size = {width, height};
	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);
}