Merge 1.9.0-beta2

This commit is contained in:
Pavel Stupnikov
2019-02-14 00:47:22 +03:00
1364 changed files with 22213 additions and 10721 deletions

View File

@@ -1,4 +1,4 @@
/* $Id: window.cpp 27934 2017-12-09 19:21:41Z michi_cc $ */
/* $Id$ */
/*
* This file is part of OpenTTD.
@@ -38,6 +38,9 @@
#include "error.h"
#include "game/game.hpp"
#include "video/video_driver.hpp"
#include "framerate_type.h"
#include "network/network_func.h"
#include "guitimer_func.h"
#include "safeguards.h"
@@ -50,7 +53,7 @@ enum ViewportAutoscrolling {
};
static Point _drag_delta; ///< delta between mouse cursor and upper left corner of dragged window
static Window *_mouseover_last_w = NULL; ///< Window of the last #MOUSEOVER event.
static Window *_mouseover_last_w = NULL; ///< Window of the last OnMouseOver event.
static Window *_last_scroll_window = NULL; ///< Window of the last scroll event.
/** List of windows opened at the screen sorted from the front. */
@@ -654,7 +657,7 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count)
/* Clicked on a widget that is not disabled.
* So unless the clicked widget is the caption bar, change focus to this widget.
* Exception: In the OSK we always want the editbox to stay focussed. */
* Exception: In the OSK we always want the editbox to stay focused. */
if (widget_type != WWT_CAPTION && w->window_class != WC_OSK) {
/* focused_widget_changed is 'now' only true if the window this widget
* is in gained focus. In that case it must remain true, also if the
@@ -939,6 +942,8 @@ static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bo
void DrawOverlappedWindowForAll(int left, int top, int right, int bottom)
{
Window *w;
DrawPixelInfo *old_dpi = _cur_dpi;
DrawPixelInfo bk;
_cur_dpi = &bk;
@@ -952,6 +957,7 @@ void DrawOverlappedWindowForAll(int left, int top, int right, int bottom)
DrawOverlappedWindow(w, max(left, w->left), max(top, w->top), min(right, w->left + w->width), min(bottom, w->top + w->height));
}
}
_cur_dpi = old_dpi;
}
/**
@@ -1116,7 +1122,7 @@ Window *FindWindowById(WindowClass cls, WindowNumber number)
/**
* Find any window by its class. Useful when searching for a window that uses
* the window number as a #WindowType, like #WC_SEND_NETWORK_MSG.
* the window number as a #WindowClass, like #WC_SEND_NETWORK_MSG.
* @param cls Window class
* @return Pointer to the found window, or \c NULL if not available
*/
@@ -1432,7 +1438,6 @@ static void BringWindowToFront(Window *w)
/**
* Initializes the data (except the position and initial size) of a new Window.
* @param desc Window description.
* @param window_number Number being assigned to the new window
* @return Window pointer of the newly created window
* @pre If nested widgets are used (\a widget is \c NULL), #nested_root and #nested_array_size must be initialized.
@@ -1741,7 +1746,7 @@ static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int
int16 default_width = max(desc->GetDefaultWidth(), sm_width);
int16 default_height = max(desc->GetDefaultHeight(), sm_height);
if (desc->parent_cls != 0 /* WC_MAIN_WINDOW */ && (w = FindWindowById(desc->parent_cls, window_number)) != NULL) {
if (desc->parent_cls != WC_NONE && (w = FindWindowById(desc->parent_cls, window_number)) != NULL) {
bool rtl = _current_text_dir == TD_RTL;
if (desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) {
pt.x = w->left + (rtl ? w->width - default_width : 0);
@@ -1921,6 +1926,8 @@ void ResetWindowSystem()
static void DecreaseWindowCounters()
{
if (_scroller_click_timeout != 0) _scroller_click_timeout--;
Window *w;
FOR_ALL_WINDOWS_FROM_FRONT(w) {
if (_scroller_click_timeout == 0) {
@@ -2004,7 +2011,7 @@ static void HandleMouseOver()
{
Window *w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
/* We changed window, put a MOUSEOVER event to the last window */
/* We changed window, put an OnMouseOver 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 };
@@ -2447,7 +2454,7 @@ static EventState HandleViewportScroll()
* outside of the window and should not left-mouse scroll anymore. */
if (_last_scroll_window == NULL) _last_scroll_window = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
if (_last_scroll_window == NULL || !(_right_button_down || scrollwheel_scrolling || (_settings_client.gui.left_mouse_btn_scrolling && _left_button_down))) {
if (_last_scroll_window == NULL || !((_settings_client.gui.scroll_mode != VSM_MAP_LMB && _right_button_down) || scrollwheel_scrolling || (_settings_client.gui.scroll_mode == VSM_MAP_LMB && _left_button_down))) {
_cursor.fix_at = false;
_scrolling_viewport = false;
_last_scroll_window = NULL;
@@ -2462,20 +2469,20 @@ static EventState HandleViewportScroll()
}
Point delta;
if (_settings_client.gui.reverse_scroll || (_settings_client.gui.left_mouse_btn_scrolling && _left_button_down)) {
delta.x = -_cursor.delta.x;
delta.y = -_cursor.delta.y;
} else {
delta.x = _cursor.delta.x;
delta.y = _cursor.delta.y;
}
if (scrollwheel_scrolling) {
/* We are using scrollwheels for scrolling */
delta.x = _cursor.h_wheel;
delta.y = _cursor.v_wheel;
_cursor.v_wheel = 0;
_cursor.h_wheel = 0;
} else {
if (_settings_client.gui.scroll_mode != VSM_VIEWPORT_RMB_FIXED) {
delta.x = -_cursor.delta.x;
delta.y = -_cursor.delta.y;
} else {
delta.x = _cursor.delta.x;
delta.y = _cursor.delta.y;
}
}
/* Create a scroll-event and send it to the window */
@@ -2753,18 +2760,17 @@ static void HandleAutoscroll()
y -= vp->top;
/* here allows scrolling in both x and y axis */
#define scrollspeed 3
static const int SCROLLSPEED = 3;
if (x - 15 < 0) {
w->viewport->dest_scrollpos_x += ScaleByZoom((x - 15) * scrollspeed, vp->zoom);
w->viewport->dest_scrollpos_x += ScaleByZoom((x - 15) * SCROLLSPEED, vp->zoom);
} else if (15 - (vp->width - x) > 0) {
w->viewport->dest_scrollpos_x += ScaleByZoom((15 - (vp->width - x)) * scrollspeed, vp->zoom);
w->viewport->dest_scrollpos_x += ScaleByZoom((15 - (vp->width - x)) * SCROLLSPEED, vp->zoom);
}
if (y - 15 < 0) {
w->viewport->dest_scrollpos_y += ScaleByZoom((y - 15) * scrollspeed, vp->zoom);
w->viewport->dest_scrollpos_y += ScaleByZoom((y - 15) * SCROLLSPEED, vp->zoom);
} else if (15 - (vp->height - y) > 0) {
w->viewport->dest_scrollpos_y += ScaleByZoom((15 - (vp->height - y)) * scrollspeed, vp->zoom);
w->viewport->dest_scrollpos_y += ScaleByZoom((15 - (vp->height - y)) * SCROLLSPEED, vp->zoom);
}
#undef scrollspeed
}
enum MouseClick {
@@ -2863,21 +2869,26 @@ static void MouseLoop(MouseClick click, int mousewheel)
if (vp != NULL && (_game_mode == GM_MENU || HasModalProgress())) return;
if (mousewheel != 0) {
/* Send mousewheel event to window */
w->OnMouseWheel(mousewheel);
/* Send mousewheel event to window, unless we're scrolling a viewport or the map */
if (!scrollwheel_scrolling || (vp == NULL && w->window_class != WC_SMALLMAP)) 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
if (scrollwheel_scrolling && !(w->flags & WF_DISABLE_VP_SCROLL)) {
_scrolling_viewport = true;
_cursor.fix_at = true;
return;
}
switch (click) {
case MC_DOUBLE_LEFT:
case MC_LEFT:
if (HandleViewportClicked(vp, x, y, click == MC_DOUBLE_LEFT)) return;
if (!(w->flags & WF_DISABLE_VP_SCROLL) &&
_settings_client.gui.left_mouse_btn_scrolling) {
_settings_client.gui.scroll_mode == VSM_MAP_LMB) {
_scrolling_viewport = true;
_cursor.fix_at = false;
return;
@@ -2885,13 +2896,11 @@ static void MouseLoop(MouseClick click, int mousewheel)
break;
case MC_RIGHT:
if (!(w->flags & WF_DISABLE_VP_SCROLL)) {
if (!(w->flags & WF_DISABLE_VP_SCROLL) &&
_settings_client.gui.scroll_mode != VSM_MAP_LMB) {
_scrolling_viewport = true;
_cursor.fix_at = true;
/* clear 2D scrolling caches before we start a 2D scroll */
_cursor.h_wheel = 0;
_cursor.v_wheel = 0;
_cursor.fix_at = (_settings_client.gui.scroll_mode == VSM_VIEWPORT_RMB_FIXED ||
_settings_client.gui.scroll_mode == VSM_MAP_RMB_FIXED);
return;
}
break;
@@ -2906,7 +2915,7 @@ static void MouseLoop(MouseClick click, int mousewheel)
case MC_LEFT:
case MC_DOUBLE_LEFT:
DispatchLeftClickEvent(w, x - w->left, y - w->top, click == MC_DOUBLE_LEFT ? 2 : 1);
break;
return;
default:
if (!scrollwheel_scrolling || w == NULL || w->window_class != WC_SMALLMAP) break;
@@ -2914,11 +2923,19 @@ static void MouseLoop(MouseClick click, int mousewheel)
* Simulate a right button click so we can get started. */
FALLTHROUGH;
case MC_RIGHT: DispatchRightClickEvent(w, x - w->left, y - w->top); break;
case MC_RIGHT:
DispatchRightClickEvent(w, x - w->left, y - w->top);
return;
case MC_HOVER: DispatchHoverEvent(w, x - w->left, y - w->top); break;
case MC_HOVER:
DispatchHoverEvent(w, x - w->left, y - w->top);
break;
}
}
/* We're not doing anything with 2D scrolling, so reset the value. */
_cursor.h_wheel = 0;
_cursor.v_wheel = 0;
}
/**
@@ -3038,7 +3055,6 @@ void InputLoop()
assert(HasModalProgress() || IsLocalCompany());
CheckSoftLimit();
HandleKeyScrolling();
/* Do the actual free of the deleted windows. */
for (Window *v = _z_front_window; v != NULL; /* nothing */) {
@@ -3051,9 +3067,6 @@ void InputLoop()
free(w);
}
if (_scroller_click_timeout != 0) _scroller_click_timeout--;
DecreaseWindowCounters();
if (_input_events_this_tick != 0) {
/* The input loop is called only once per GameLoop() - so we can clear the counter here */
_input_events_this_tick = 0;
@@ -3063,7 +3076,17 @@ void InputLoop()
/* HandleMouseEvents was already called for this tick */
HandleMouseEvents();
HandleAutoscroll();
}
/**
* Dispatch OnRealtimeTick event over all windows
*/
void CallWindowRealtimeTickEvent(uint delta_ms)
{
Window *w;
FOR_ALL_WINDOWS_FROM_FRONT(w) {
w->OnRealtimeTick(delta_ms);
}
}
/**
@@ -3071,14 +3094,48 @@ void InputLoop()
*/
void UpdateWindows()
{
static uint32 last_realtime_tick = _realtime_tick;
uint delta_ms = _realtime_tick - last_realtime_tick;
last_realtime_tick = _realtime_tick;
if (delta_ms == 0) return;
PerformanceMeasurer framerate(PFE_DRAWING);
PerformanceAccumulator::Reset(PFE_DRAWWORLD);
CallWindowRealtimeTickEvent(delta_ms);
#ifdef ENABLE_NETWORK
static GUITimer network_message_timer = GUITimer(1);
if (network_message_timer.Elapsed(delta_ms)) {
network_message_timer.SetInterval(1000);
NetworkChatMessageLoop();
}
#endif
Window *w;
static int highlight_timer = 1;
if (--highlight_timer == 0) {
highlight_timer = 15;
static GUITimer window_timer = GUITimer(1);
if (window_timer.Elapsed(delta_ms)) {
if (_network_dedicated) window_timer.SetInterval(MILLISECONDS_PER_TICK);
extern int _caret_timer;
_caret_timer += 3;
CursorTick();
HandleKeyScrolling();
HandleAutoscroll();
DecreaseWindowCounters();
}
static GUITimer highlight_timer = GUITimer(1);
if (highlight_timer.Elapsed(delta_ms)) {
highlight_timer.SetInterval(450);
_window_highlight_colour = !_window_highlight_colour;
}
if (!_pause_mode || _game_mode == GM_EDITOR || _settings_game.construction.command_pause_level > CMDPL_NO_CONSTRUCTION) MoveAllTextEffects(delta_ms);
FOR_ALL_WINDOWS_FROM_FRONT(w) {
w->ProcessScheduledInvalidations();
w->ProcessHighlightedInvalidations();
@@ -3088,21 +3145,23 @@ void UpdateWindows()
* But still empty the invalidation queues above. */
if (_network_dedicated) return;
static int we4_timer = 0;
int t = we4_timer + 1;
static GUITimer hundredth_timer = GUITimer(1);
if (hundredth_timer.Elapsed(delta_ms)) {
hundredth_timer.SetInterval(3000); // Historical reason: 100 * MILLISECONDS_PER_TICK
if (t >= 100) {
FOR_ALL_WINDOWS_FROM_FRONT(w) {
w->OnHundredthTick();
}
t = 0;
}
we4_timer = t;
FOR_ALL_WINDOWS_FROM_FRONT(w) {
if ((w->flags & WF_WHITE_BORDER) && --w->white_border_timer == 0) {
CLRBITS(w->flags, WF_WHITE_BORDER);
w->SetDirty();
if (window_timer.HasElapsed()) {
window_timer.SetInterval(MILLISECONDS_PER_TICK);
FOR_ALL_WINDOWS_FROM_FRONT(w) {
if ((w->flags & WF_WHITE_BORDER) && --w->white_border_timer == 0) {
CLRBITS(w->flags, WF_WHITE_BORDER);
w->SetDirty();
}
}
}
@@ -3252,13 +3311,13 @@ void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
}
/**
* Dispatch WE_TICK event over all windows
* Dispatch OnGameTick event over all windows
*/
void CallWindowTickEvent()
void CallWindowGameTickEvent()
{
Window *w;
FOR_ALL_WINDOWS_FROM_FRONT(w) {
w->OnTick();
w->OnGameTick();
}
}
@@ -3462,8 +3521,9 @@ void ChangeVehicleViewports(VehicleID from_index, VehicleID to_index)
*/
void RelocateAllWindows(int neww, int newh)
{
Window *w;
DeleteWindowById(WC_DROPDOWN_MENU, 0);
Window *w;
FOR_ALL_WINDOWS_FROM_BACK(w) {
int left, top;
/* XXX - this probably needs something more sane. For example specifying