Changeset - r27623:94a2107d67c7
[Not reviewed]
master
0 1 0
PeterN - 16 months ago 2023-06-20 19:34:05
peter1138@openttd.org
Fix #11043: Don't choose toolbar dropdown option if focus is lost. (#11044)

Since dropdown menus now get closed if they lose focus, 'instant close' dropdowns (i.e. the toolbar dropdowns) should no longer execute their action to avoid unintended actions.
1 file changed with 4 insertions and 1 deletions:
0 comments (0 inline, 0 general)
src/widgets/dropdown.cpp
Show inline comments
 
@@ -154,97 +154,100 @@ struct DropdownWindow : Window {
 
		NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_DM_ITEMS);
 
		nwi->SetMinimalSizeAbsolute(items_width, size.height + WidgetDimensions::scaled.fullbevel.Vertical() * 2);
 
		nwi->colour = wi_colour;
 

	
 
		nwi = this->GetWidget<NWidgetCore>(WID_DM_SCROLL);
 
		nwi->colour = wi_colour;
 

	
 
		this->GetWidget<NWidgetStacked>(WID_DM_SHOW_SCROLL)->SetDisplayedPlane(scroll ? 0 : SZSP_NONE);
 

	
 
		this->FinishInitNested(0);
 
		CLRBITS(this->flags, WF_WHITE_BORDER);
 

	
 
		/* Total length of list */
 
		int list_height = 0;
 
		for (const auto &item : this->list) {
 
			list_height += item->Height(items_width);
 
		}
 

	
 
		/* Capacity is the average number of items visible */
 
		this->vscroll->SetCapacity(size.height * this->list.size() / list_height);
 
		this->vscroll->SetCount(this->list.size());
 

	
 
		this->parent           = parent;
 
		this->parent_button    = button;
 
		this->selected_index   = selected;
 
		this->click_delay      = 0;
 
		this->drag_mode        = true;
 
		this->instant_close    = instant_close;
 
	}
 

	
 
	void Close() override
 
	{
 
		/* Finish closing the dropdown, so it doesn't affect new window placement.
 
		 * Also mark it dirty in case the callback deals with the screen. (e.g. screenshots). */
 
		this->Window::Close();
 

	
 
		Point pt = _cursor.pos;
 
		pt.x -= this->parent->left;
 
		pt.y -= this->parent->top;
 
		this->parent->OnDropdownClose(pt, this->parent_button, this->selected_index, this->instant_close);
 

	
 
		/* Set flag on parent widget to indicate that we have just closed. */
 
		NWidgetCore *nwc = this->parent->GetWidget<NWidgetCore>(this->parent_button);
 
		if (nwc != nullptr) SetBit(nwc->disp_flags, NDB_DROPDOWN_CLOSED);
 
	}
 

	
 
	void OnFocusLost(bool closing) override
 
	{
 
		if (!closing) this->Close();
 
		if (!closing) {
 
			this->instant_close = false;
 
			this->Close();
 
		}
 
	}
 

	
 
	Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override
 
	{
 
		return this->position;
 
	}
 

	
 
	/**
 
	 * Find the dropdown item under the cursor.
 
	 * @param[out] value Selected item, if function returns \c true.
 
	 * @return Cursor points to a dropdown item.
 
	 */
 
	bool GetDropDownItem(int &value)
 
	{
 
		if (GetWidgetFromPos(this, _cursor.pos.x - this->left, _cursor.pos.y - this->top) < 0) return false;
 

	
 
		const Rect &r = this->GetWidget<NWidgetBase>(WID_DM_ITEMS)->GetCurrentRect().Shrink(WidgetDimensions::scaled.fullbevel);
 
		int y     = _cursor.pos.y - this->top - r.top - WidgetDimensions::scaled.fullbevel.top;
 
		int width = r.Width();
 
		int pos   = this->vscroll->GetPosition();
 

	
 
		for (const auto &item : this->list) {
 
			/* Skip items that are scrolled up */
 
			if (--pos >= 0) continue;
 

	
 
			int item_height = item->Height(width);
 

	
 
			if (y < item_height) {
 
				if (item->masked || !item->Selectable()) return false;
 
				value = item->result;
 
				return true;
 
			}
 

	
 
			y -= item_height;
 
		}
 

	
 
		return false;
 
	}
 

	
 
	void DrawWidget(const Rect &r, int widget) const override
 
	{
 
		if (widget != WID_DM_ITEMS) return;
 

	
 
		Colours colour = this->GetWidget<NWidgetCore>(widget)->colour;
 

	
 
		Rect ir = r.Shrink(WidgetDimensions::scaled.fullbevel).Shrink(RectPadding::zero, WidgetDimensions::scaled.fullbevel);
 
		int y = ir.top;
 
		int pos = this->vscroll->GetPosition();
0 comments (0 inline, 0 general)