@@ -1337,96 +1337,114 @@ static void DecreaseWindowCounters()
if ((w->flags4 & WF_TIMEOUT_MASK) && !(--w->flags4 & WF_TIMEOUT_MASK)) {
w->OnTimeout();
if (w->desc_flags & WDF_UNCLICK_BUTTONS) w->RaiseButtons(true);
}
Window *GetCallbackWnd()
{
return FindWindowById(_thd.window_class, _thd.window_number);
static void HandlePlacePresize()
if (_special_mouse_mode != WSM_PRESIZE) return;
Window *w = GetCallbackWnd();
if (w == NULL) return;
Point pt = GetTileBelowCursor();
if (pt.x == -1) {
_thd.selend.x = -1;
return;
w->OnPlacePresize(pt, TileVirtXY(pt.x, pt.y));
static bool HandleDragDrop()
if (_special_mouse_mode != WSM_DRAGDROP) return true;
if (_left_button_down) return false;
if (w != NULL) {
/* send an event in client coordinates. */
Point pt;
pt.x = _cursor.pos.x - w->left;
pt.y = _cursor.pos.y - w->top;
w->OnDragDrop(pt, GetWidgetFromPos(w, pt.x, pt.y));
ResetObjectToPlace();
return false;
static bool HandleMouseDrag()
if (!_left_button_down || (_cursor.delta.x == 0 && _cursor.delta.y == 0)) return true;
/* Send an event in client coordinates. */
w->OnMouseDrag(pt, GetWidgetFromPos(w, pt.x, pt.y));
static bool HandleMouseOver()
Window *w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
/* We changed window, put a MOUSEOVER event to the last window */
if (_mouseover_last_w != NULL && _mouseover_last_w != w) {
/* Reset mouse-over coordinates of previous window */
Point pt = { -1, -1 };
_mouseover_last_w->OnMouseOver(pt, 0);
/* _mouseover_last_w will get reset when the window is deleted, see DeleteWindow() */
_mouseover_last_w = w;
Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top };
const NWidgetCore *widget = w->nested_root->GetWidgetFromPos(pt.x, pt.y);
if (widget != NULL) w->OnMouseOver(pt, widget->index);
/* Mouseover never stops execution */
return true;
/**
* Resize the window.
* Update all the widgets of a window based on their resize flags
* Both the areas of the old window and the new sized window are set dirty
* ensuring proper redrawal.
* @param w Window to resize
* @param delta_x Delta x-size of changed window (positive if larger, etc.)
* @param delta_y Delta y-size of changed window
*/
void ResizeWindow(Window *w, int delta_x, int delta_y)
if (delta_x != 0 || delta_y != 0) {
w->SetDirty();
uint new_xinc = max(0, (w->nested_root->resize_x == 0) ? 0 : (int)(w->nested_root->current_x - w->nested_root->smallest_x) + delta_x);
uint new_yinc = max(0, (w->nested_root->resize_y == 0) ? 0 : (int)(w->nested_root->current_y - w->nested_root->smallest_y) + delta_y);
assert(w->nested_root->resize_x == 0 || new_xinc % w->nested_root->resize_x == 0);
assert(w->nested_root->resize_y == 0 || new_yinc % w->nested_root->resize_y == 0);
w->nested_root->AssignSizePosition(ST_RESIZE, 0, 0, w->nested_root->smallest_x + new_xinc, w->nested_root->smallest_y + new_yinc, _dynlang.text_dir == TD_RTL);
w->width = w->nested_root->current_x;
w->height = w->nested_root->current_y;
@@ -2012,96 +2030,97 @@ static void ScrollMainViewport(int x, in
* Describes all the different arrow key combinations the game allows
* when it is in scrolling mode.
* The real arrow keys are bitwise numbered as
* 1 = left
* 2 = up
* 4 = right
* 8 = down
static const int8 scrollamt[16][2] = {
{ 0, 0}, ///< no key specified
{-2, 0}, ///< 1 : left
{ 0, -2}, ///< 2 : up
{-2, -1}, ///< 3 : left + up
{ 2, 0}, ///< 4 : right
{ 0, 0}, ///< 5 : left + right = nothing
{ 2, -1}, ///< 6 : right + up
{ 0, -2}, ///< 7 : right + left + up = up
{ 0, 2}, ///< 8 : down
{-2, 1}, ///< 9 : down + left
{ 0, 0}, ///< 10 : down + up = nothing
{-2, 0}, ///< 11 : left + up + down = left
{ 2, 1}, ///< 12 : down + right
{ 0, 2}, ///< 13 : left + right + down = down
{ 2, 0}, ///< 14 : right + up + down = right
{ 0, 0}, ///< 15 : left + up + right + down = nothing
};
static void HandleKeyScrolling()
/*
* Check that any of the dirkeys is pressed and that the focused window
* dont has an edit-box as focused widget.
if (_dirkeys && !EditBoxInGlobalFocus()) {
int factor = _shift_pressed ? 50 : 10;
ScrollMainViewport(scrollamt[_dirkeys][0] * factor, scrollamt[_dirkeys][1] * factor);
static void MouseLoop(MouseClick click, int mousewheel)
HandlePlacePresize();
UpdateTileSelection();
if (!VpHandlePlaceSizingDrag()) return;
if (!HandleMouseDrag()) return;
if (!HandleDragDrop()) return;
if (!HandleWindowDragging()) return;
if (!HandleScrollbarScrolling()) return;
if (!HandleViewportScroll()) return;
if (!HandleMouseOver()) return;
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 (!MaybeBringWindowToFront(w)) return;
ViewPort *vp = IsPtInWindowViewport(w, x, y);
/* Don't allow any action in a viewport if either in menu of in generating world */
if (vp != NULL && (_game_mode == GM_MENU || IsGeneratingWorld())) return;
if (mousewheel != 0) {
if (_settings_client.gui.scrollwheel_scrolling == 0) {
/* Send mousewheel event to window */
w->OnMouseWheel(mousewheel);
/* Dispatch a MouseWheelEvent for widgets if it is not a viewport */
if (vp == NULL) DispatchMouseWheelEvent(w, w->nested_root->GetWidgetFromPos(x - w->left, y - w->top), mousewheel);
if (vp != NULL) {
if (scrollwheel_scrolling) click = MC_RIGHT; // we are using the scrollwheel in a viewport, so we emulate right mouse button
switch (click) {
case MC_DOUBLE_LEFT:
case MC_LEFT:
DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite);
if (_thd.place_mode != HT_NONE &&
/* query button and place sign button work in pause mode */
_cursor.sprite != SPR_CURSOR_QUERY &&
_cursor.sprite != SPR_CURSOR_SIGN &&
_pause_mode != PM_UNPAUSED &&
!_cheats.build_in_pause.value) {
if (_thd.place_mode == HT_NONE) {
if (!HandleViewportClicked(vp, x, y) &&
!(w->flags4 & WF_DISABLE_VP_SCROLL) &&
@@ -612,96 +612,103 @@ public:
* and while re-initializing the window. Only for widgets that render text initializing is requested.
* @param widget Widget number.
virtual void SetStringParameters(int widget) const {}
* Called when window gains focus
virtual void OnFocus() {}
* Called when window looses focus
virtual void OnFocusLost() {}
* A key has been pressed.
* @param key the Unicode value of the key.
* @param keycode the untranslated key code including shift state.
* @return #ES_HANDLED if the key press has been handled and no other
* window should receive the event.
virtual EventState OnKeyPress(uint16 key, uint16 keycode) { return ES_NOT_HANDLED; }
* The state of the control key has changed
* @return #ES_HANDLED if the change has been handled and no other
virtual EventState OnCTRLStateChange() { return ES_NOT_HANDLED; }
* A click with the left mouse button has been made on the window.
* @param pt the point inside the window that has been clicked.
* @param widget the clicked widget.
* @param click_count Number of fast consecutive clicks at same position
virtual void OnClick(Point pt, int widget, int click_count) {}
* A click with the right mouse button has been made on the window.
virtual void OnRightClick(Point pt, int widget) {}
* An 'object' is being dragged at the provided position, highlight the target if possible.
* @param pt The point inside the window that the mouse hovers over.
* @param widget The widget the mouse hovers over.
virtual void OnMouseDrag(Point pt, int widget) {}
* A dragged 'object' has been released.
* @param pt the point inside the window where the release took place.
* @param widget the widget where the release took place.
virtual void OnDragDrop(Point pt, int widget) {}
* Handle the request for (viewport) scrolling.
* @param delta the amount the viewport must be scrolled.
virtual void OnScroll(Point delta) {}
* The mouse is currently moving over the window or has just moved outside
* of the window. In the latter case pt is (-1, -1).
* @param pt the point inside the window that the mouse hovers over.
* @param widget the widget the mouse hovers over.
virtual void OnMouseOver(Point pt, int widget) {}
* The mouse wheel has been turned.
* @param wheel the amount of movement of the mouse wheel.
virtual void OnMouseWheel(int wheel) {}
* Called for every mouse loop run, which is at least once per (game) tick.
virtual void OnMouseLoop() {}
* Called once per (game) tick.
virtual void OnTick() {}
* Called once every 100 (game) ticks.
virtual void OnHundredthTick() {}
* Called when this window's timeout has been reached.
virtual void OnTimeout() {}
Status change: