Changeset - r23337:5d348848d78f
[Not reviewed]
master
0 3 0
Peter Nelson - 6 years ago 2019-02-14 06:25:17
peter1138@openttd.org
Codechange: Change scrolling_scrollbar to mouse_capture_widget, and dispatch OnClick() event if widget is not a scrollbar.

This allows any widget to support mouse capture.
3 files changed with 56 insertions and 37 deletions:
0 comments (0 inline, 0 general)
src/widget.cpp
Show inline comments
 
@@ -90,45 +90,45 @@ static void ScrollbarClickPositioning(Wi
 
		button_size = NWidgetScrollbar::GetHorizontalDimension().width;
 
	} else {
 
		pos = y;
 
		button_size = NWidgetScrollbar::GetVerticalDimension().height;
 
	}
 
	if (pos < mi + button_size) {
 
		/* Pressing the upper button? */
 
		SetBit(sb->disp_flags, NDB_SCROLLBAR_UP);
 
		if (_scroller_click_timeout <= 1) {
 
			_scroller_click_timeout = 3;
 
			sb->UpdatePosition(rtl ? 1 : -1);
 
		}
 
		w->scrolling_scrollbar = sb->index;
 
		w->mouse_capture_widget = sb->index;
 
	} else if (pos >= ma - button_size) {
 
		/* Pressing the lower button? */
 
		SetBit(sb->disp_flags, NDB_SCROLLBAR_DOWN);
 

	
 
		if (_scroller_click_timeout <= 1) {
 
			_scroller_click_timeout = 3;
 
			sb->UpdatePosition(rtl ? -1 : 1);
 
		}
 
		w->scrolling_scrollbar = sb->index;
 
		w->mouse_capture_widget = sb->index;
 
	} else {
 
		Point pt = HandleScrollbarHittest(sb, mi, ma, sb->type == NWID_HSCROLLBAR);
 

	
 
		if (pos < pt.x) {
 
			sb->UpdatePosition(rtl ? 1 : -1, Scrollbar::SS_BIG);
 
		} else if (pos > pt.y) {
 
			sb->UpdatePosition(rtl ? -1 : 1, Scrollbar::SS_BIG);
 
		} else {
 
			_scrollbar_start_pos = pt.x - mi - button_size;
 
			_scrollbar_size = ma - mi - button_size * 2;
 
			w->scrolling_scrollbar = sb->index;
 
			w->mouse_capture_widget = sb->index;
 
			_cursorpos_drag_start = _cursor.pos;
 
		}
 
	}
 

	
 
	w->SetDirty();
 
}
 

	
 
/**
 
 * Special handling for the scrollbar widget type.
 
 * Handles the special scrolling buttons and other scrolling.
 
 * @param w Window on which a scroll was performed.
 
 * @param nw Pointer to the scrollbar widget.
 
@@ -2029,25 +2029,25 @@ void NWidgetScrollbar::Draw(const Window
 

	
 
	Rect r;
 
	r.left = this->pos_x;
 
	r.right = this->pos_x + this->current_x - 1;
 
	r.top = this->pos_y;
 
	r.bottom = this->pos_y + this->current_y - 1;
 

	
 
	const DrawPixelInfo *dpi = _cur_dpi;
 
	if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return;
 

	
 
	bool up_lowered = HasBit(this->disp_flags, NDB_SCROLLBAR_UP);
 
	bool down_lowered = HasBit(this->disp_flags, NDB_SCROLLBAR_DOWN);
 
	bool middle_lowered = !(this->disp_flags & ND_SCROLLBAR_BTN) && w->scrolling_scrollbar == this->index;
 
	bool middle_lowered = !(this->disp_flags & ND_SCROLLBAR_BTN) && w->mouse_capture_widget == this->index;
 

	
 
	if (this->type == NWID_HSCROLLBAR) {
 
		DrawHorizontalScrollbar(r, this->colour, up_lowered, middle_lowered, down_lowered, this);
 
	} else {
 
		DrawVerticalScrollbar(r, this->colour, up_lowered, middle_lowered, down_lowered, this);
 
	}
 

	
 
	if (this->IsDisabled()) {
 
		GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER);
 
	}
 
}
 

	
src/window.cpp
Show inline comments
 
@@ -1837,25 +1837,25 @@ void Window::FinishInitNested(WindowNumb
 
 * @param window_number Number of the new window.
 
 */
 
void Window::InitNested(WindowNumber window_number)
 
{
 
	this->CreateNestedTree(false);
 
	this->FinishInitNested(window_number);
 
}
 

	
 
/**
 
 * Empty constructor, initialization has been moved to #InitNested() called from the constructor of the derived class.
 
 * @param desc The description of the window.
 
 */
 
Window::Window(WindowDesc *desc) : window_desc(desc), scrolling_scrollbar(-1)
 
Window::Window(WindowDesc *desc) : window_desc(desc), mouse_capture_widget(-1)
 
{
 
}
 

	
 
/**
 
 * Do a search for a window at specific coordinates. For this we start
 
 * at the topmost window, obviously and work our way down to the bottom
 
 * @param x position x to query
 
 * @param y position y to query
 
 * @return a pointer to the found window if any, NULL otherwise
 
 */
 
Window *FindWindowFromPt(int x, int y)
 
{
 
@@ -1925,25 +1925,25 @@ static void DecreaseWindowCounters()
 
	if (_scroller_click_timeout != 0) _scroller_click_timeout--;
 

	
 
	Window *w;
 
	FOR_ALL_WINDOWS_FROM_FRONT(w) {
 
		if (_scroller_click_timeout == 0) {
 
			/* Unclick scrollbar buttons if they are pressed. */
 
			for (uint i = 0; i < w->nested_array_size; i++) {
 
				NWidgetBase *nwid = w->nested_array[i];
 
				if (nwid != NULL && (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR)) {
 
					NWidgetScrollbar *sb = static_cast<NWidgetScrollbar*>(nwid);
 
					if (sb->disp_flags & (ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN)) {
 
						sb->disp_flags &= ~(ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN);
 
						w->scrolling_scrollbar = -1;
 
						w->mouse_capture_widget = -1;
 
						sb->SetDirty(w);
 
					}
 
				}
 
			}
 
		}
 

	
 
		/* Handle editboxes */
 
		for (SmallMap<int, QueryString*>::Pair *it = w->querystrings.Begin(); it != w->querystrings.End(); ++it) {
 
			it->second->HandleEditBox(w, it->first);
 
		}
 

	
 
		w->OnMouseLoop();
 
@@ -2377,65 +2377,84 @@ static void StartWindowSizing(Window *w,
 
	w->flags |= to_left ? WF_SIZING_LEFT : WF_SIZING_RIGHT;
 
	w->flags &= ~WF_CENTERED;
 
	_dragging_window = true;
 

	
 
	_drag_delta.x = _cursor.pos.x;
 
	_drag_delta.y = _cursor.pos.y;
 

	
 
	BringWindowToFront(w);
 
	DeleteWindowById(WC_DROPDOWN_MENU, 0);
 
}
 

	
 
/**
 
 * handle scrollbar scrolling with the mouse.
 
 * Handle scrollbar scrolling with the mouse.
 
 * @param w window with active scrollbar.
 
 */
 
static void HandleScrollbarScrolling(Window *w)
 
{
 
	int i;
 
	NWidgetScrollbar *sb = w->GetWidget<NWidgetScrollbar>(w->mouse_capture_widget);
 
	bool rtl = false;
 

	
 
	if (sb->type == NWID_HSCROLLBAR) {
 
		i = _cursor.pos.x - _cursorpos_drag_start.x;
 
		rtl = _current_text_dir == TD_RTL;
 
	} else {
 
		i = _cursor.pos.y - _cursorpos_drag_start.y;
 
	}
 

	
 
	if (sb->disp_flags & ND_SCROLLBAR_BTN) {
 
		if (_scroller_click_timeout == 1) {
 
			_scroller_click_timeout = 3;
 
			sb->UpdatePosition(rtl == HasBit(sb->disp_flags, NDB_SCROLLBAR_UP) ? 1 : -1);
 
			w->SetDirty();
 
		}
 
		return;
 
	}
 

	
 
	/* Find the item we want to move to and make sure it's inside bounds. */
 
	int pos = min(max(0, i + _scrollbar_start_pos) * sb->GetCount() / _scrollbar_size, max(0, sb->GetCount() - sb->GetCapacity()));
 
	if (rtl) pos = max(0, sb->GetCount() - sb->GetCapacity() - pos);
 
	if (pos != sb->GetPosition()) {
 
		sb->SetPosition(pos);
 
		w->SetDirty();
 
	}
 
}
 

	
 
/**
 
 * Handle active widget (mouse draggin on widget) with the mouse.
 
 * @return State of handling the event.
 
 */
 
static EventState HandleScrollbarScrolling()
 
static EventState HandleActiveWidget()
 
{
 
	Window *w;
 
	FOR_ALL_WINDOWS_FROM_BACK(w) {
 
		if (w->scrolling_scrollbar >= 0) {
 
		if (w->mouse_capture_widget >= 0) {
 
			/* Abort if no button is clicked any more. */
 
			if (!_left_button_down) {
 
				w->scrolling_scrollbar = -1;
 
				w->mouse_capture_widget = -1;
 
				w->SetDirty();
 
				return ES_HANDLED;
 
			}
 

	
 
			int i;
 
			NWidgetScrollbar *sb = w->GetWidget<NWidgetScrollbar>(w->scrolling_scrollbar);
 
			bool rtl = false;
 

	
 
			if (sb->type == NWID_HSCROLLBAR) {
 
				i = _cursor.pos.x - _cursorpos_drag_start.x;
 
				rtl = _current_text_dir == TD_RTL;
 
			/* If cursor hasn't moved, there is nothing to do. */
 
			if (_cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED;
 

	
 
			/* Handle scrollbar internally, or dispatch click event */
 
			WidgetType type = w->GetWidget<NWidgetBase>(w->mouse_capture_widget)->type;
 
			if (type == NWID_VSCROLLBAR || type == NWID_HSCROLLBAR) {
 
				HandleScrollbarScrolling(w);
 
			} else {
 
				i = _cursor.pos.y - _cursorpos_drag_start.y;
 
			}
 

	
 
			if (sb->disp_flags & ND_SCROLLBAR_BTN) {
 
				if (_scroller_click_timeout == 1) {
 
					_scroller_click_timeout = 3;
 
					sb->UpdatePosition(rtl == HasBit(sb->disp_flags, NDB_SCROLLBAR_UP) ? 1 : -1);
 
					w->SetDirty();
 
				}
 
				return ES_HANDLED;
 
			}
 

	
 
			/* Find the item we want to move to and make sure it's inside bounds. */
 
			int pos = min(max(0, i + _scrollbar_start_pos) * sb->GetCount() / _scrollbar_size, max(0, sb->GetCount() - sb->GetCapacity()));
 
			if (rtl) pos = max(0, sb->GetCount() - sb->GetCapacity() - pos);
 
			if (pos != sb->GetPosition()) {
 
				sb->SetPosition(pos);
 
				w->SetDirty();
 
				Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top };
 
				w->OnClick(pt, w->mouse_capture_widget, 0);
 
			}
 
			return ES_HANDLED;
 
		}
 
	}
 

	
 
	return ES_NOT_HANDLED;
 
}
 

	
 
/**
 
 * Handle viewport scrolling with the mouse.
 
 * @return State of handling the event.
 
 */
 
@@ -2836,25 +2855,25 @@ static void HandleKeyScrolling()
 
static void MouseLoop(MouseClick click, int mousewheel)
 
{
 
	/* World generation is multithreaded and messes with companies.
 
	 * But there is no company related window open anyway, so _current_company is not used. */
 
	assert(HasModalProgress() || IsLocalCompany());
 

	
 
	HandlePlacePresize();
 
	UpdateTileSelection();
 

	
 
	if (VpHandlePlaceSizingDrag()  == ES_HANDLED) return;
 
	if (HandleMouseDragDrop()      == ES_HANDLED) return;
 
	if (HandleWindowDragging()     == ES_HANDLED) return;
 
	if (HandleScrollbarScrolling() == ES_HANDLED) return;
 
	if (HandleActiveWidget()       == ES_HANDLED) return;
 
	if (HandleViewportScroll()     == ES_HANDLED) return;
 

	
 
	HandleMouseOver();
 

	
 
	bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0);
 
	if (click == MC_NONE && mousewheel == 0 && !scrollwheel_scrolling) return;
 

	
 
	int x = _cursor.pos.x;
 
	int y = _cursor.pos.y;
 
	Window *w = FindWindowFromPt(x, y);
 
	if (w == NULL) return;
 

	
src/window_gui.h
Show inline comments
 
@@ -318,25 +318,25 @@ public:
 

	
 
	Owner owner;        ///< The owner of the content shown in this window. Company colour is acquired from this variable.
 

	
 
	ViewportData *viewport;          ///< Pointer to viewport data, if present.
 
	const NWidgetCore *nested_focus; ///< Currently focused nested widget, or \c NULL if no nested widget has focus.
 
	SmallMap<int, QueryString*> querystrings; ///< QueryString associated to WWT_EDITBOX widgets.
 
	NWidgetBase *nested_root;        ///< Root of the nested tree.
 
	NWidgetBase **nested_array;      ///< Array of pointers into the tree. Do not access directly, use #Window::GetWidget() instead.
 
	uint nested_array_size;          ///< Size of the nested array.
 
	NWidgetStacked *shade_select;    ///< Selection widget (#NWID_SELECTION) to use for shading the window. If \c NULL, window cannot shade.
 
	Dimension unshaded_size;         ///< Last known unshaded size (only valid while shaded).
 

	
 
	int scrolling_scrollbar;         ///< Widgetindex of just being dragged scrollbar. -1 if none is active.
 
	int mouse_capture_widget;        ///< Widgetindex of current mouse capture widget (e.g. dragged scrollbar). -1 if no widget has mouse capture.
 

	
 
	Window *parent;                  ///< Parent window.
 
	Window *z_front;                 ///< The window in front of us in z-order.
 
	Window *z_back;                  ///< The window behind us in z-order.
 

	
 
	template <class NWID>
 
	inline const NWID *GetWidget(uint widnum) const;
 
	template <class NWID>
 
	inline NWID *GetWidget(uint widnum);
 

	
 
	const Scrollbar *GetScrollbar(uint widnum) const;
 
	Scrollbar *GetScrollbar(uint widnum);
0 comments (0 inline, 0 general)