69 Point _cursorpos_drag_start;
71 int _scrollbar_start_pos;
73 byte _scroller_click_timeout = 0;
95 parent_cls(parent_class),
98 nwid_parts(nwid_parts),
99 nwid_length(nwid_length),
104 default_width_trad(def_width_trad),
105 default_height_trad(def_height_trad)
108 *_window_descs->
Append() =
this;
111 WindowDesc::~WindowDesc()
113 _window_descs->
Erase(_window_descs->
Find(
this));
144 if ((*it)->ini_key == NULL)
continue;
155 if ((*a)->ini_key != NULL && (*b)->ini_key != NULL)
return strcmp((*a)->ini_key, (*b)->ini_key);
156 return ((*b)->ini_key != NULL ? 1 : 0) - ((*a)->ini_key != NULL ? 1 : 0);
170 if ((*it)->ini_key == NULL)
continue;
201 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(widget);
202 if (line_height < 0) line_height = wid->
resize_y;
203 if (clickpos < (
int)wid->
pos_y + padding)
return INT_MAX;
204 return (clickpos - (
int)wid->
pos_y - padding) / line_height;
213 NWidgetBase *nwid = this->GetWidget<NWidgetBase>(i);
214 if (nwid == NULL)
continue;
216 if (nwid->IsHighlighted()) {
217 nwid->SetHighlighted(TC_INVALID);
234 NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget_index);
235 if (nwid == NULL)
return;
237 nwid->SetHighlighted(highlighted_colour);
240 if (highlighted_colour != TC_INVALID) {
247 NWidgetBase *nwid = this->GetWidget<NWidgetBase>(i);
248 if (nwid == NULL)
continue;
249 if (!nwid->IsHighlighted())
continue;
267 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget_index);
268 if (nwid == NULL)
return false;
270 return nwid->IsHighlighted();
282 if (widget < 0)
return;
293 NWidgetCore *nwi2 = this->GetWidget<NWidgetCore>(widget);
309 return this->GetWidget<NWidgetScrollbar>(widnum);
319 return this->GetWidget<NWidgetScrollbar>(widnum);
410 Rect r = {0, 0, 0, 0};
434 if (_focused_window == w)
return;
437 if (_focused_window != NULL) {
442 Window *old_focused = _focused_window;
446 if (old_focused != NULL) old_focused->
OnFocusLost();
447 if (_focused_window != NULL) _focused_window->
OnFocus();
457 if (_focused_window == NULL)
return false;
491 if (this->GetWidget<NWidgetCore>(widget_index) == this->
nested_focus)
return false;
497 this->
nested_focus = this->GetWidget<NWidgetCore>(widget_index);
520 va_start(wdg_list, widgets);
524 widgets = va_arg(wdg_list,
int);
539 va_start(wdg_list, widgets);
543 widgets = va_arg(wdg_list,
int);
558 if (((type & ~WWB_PUSHBUTTON) <
WWT_LAST || type == NWID_PUSHBUTTON_DROPDOWN) &&
594 NWidgetCore *nw = this->GetWidget<NWidgetCore>(hotkey);
637 bool focused_widget_changed =
false;
639 if (_focused_window != w &&
642 focused_widget_changed =
true;
646 if (nw == NULL)
return;
651 int widget_index = nw->
index;
677 switch (widget_type) {
685 if (query != NULL) query->ClickEditBox(w, pt, widget_index, click_count, focused_widget_changed);
747 if (widget_index < 0)
return;
755 w->
OnClick(pt, widget_index, click_count);
767 if (wid == NULL)
return;
770 if (wid->
index >= 0) {
794 if (wid == NULL)
return;
803 if (wid->
index < 0)
return;
818 if (nwid == NULL)
return;
884 left < v->left + v->
width &&
885 top < v->top + v->
height) {
889 if (left < (x = v->
left)) {
901 if (top < (x = v->
top)) {
919 dp->width = right - left;
920 dp->height = bottom - top;
921 dp->left = left - w->
left;
922 dp->top = top - w->
top;
923 dp->pitch = _screen.pitch;
943 FOR_ALL_WINDOWS_FROM_BACK(w) {
947 left < w->left + w->
width &&
948 top < w->top + w->
height) {
975 int window_width = this->
width;
976 int window_height = this->
height;
988 window_width =
max(window_width + rx, this->
width);
989 window_height =
max(window_height + ry, this->
height);
1036 FOR_ALL_WINDOWS_FROM_BACK(v) {
1050 while (child != NULL) {
1067 if (_mouseover_last_w ==
this) _mouseover_last_w = NULL;
1070 if (_last_scroll_window ==
this) _last_scroll_window = NULL;
1073 if (_focused_window ==
this) {
1075 _focused_window = NULL;
1080 if (this->
viewport != NULL) DeleteWindowViewport(
this);
1108 FOR_ALL_WINDOWS_FROM_BACK(w) {
1124 FOR_ALL_WINDOWS_FROM_BACK(w) {
1140 if (force || w == NULL ||
1158 FOR_ALL_WINDOWS_FROM_BACK(w) {
1161 goto restart_search;
1180 FOR_ALL_WINDOWS_FROM_BACK(w) {
1181 if (w->
owner ==
id) {
1183 goto restart_search;
1201 FOR_ALL_WINDOWS_FROM_BACK(w) {
1202 if (w->
owner != old_owner)
continue;
1219 w->
owner = new_owner;
1249 static inline bool IsVitalWindow(
const Window *w)
1275 uint z_priority = 0;
1353 if (_z_front_window == NULL) {
1355 _z_front_window = _z_back_window = w;
1360 uint last_z_priority = UINT_MAX;
1375 _z_back_window->
z_back = w;
1377 }
else if (v == _z_front_window) {
1382 _z_front_window = w;
1401 assert(_z_front_window == w);
1402 _z_front_window = w->
z_back;
1408 assert(_z_back_window == w);
1484 this->
width = sm_width;
1485 this->
height = sm_height;
1500 def_width =
max(def_width, this->
width);
1501 def_height =
max(def_height, this->
height);
1507 if (this->
width != def_width || this->
height != def_height) {
1509 int free_height = _screen.height;
1511 if (wt != NULL) free_height -= wt->
height;
1513 if (wt != NULL) free_height -= wt->
height;
1515 int enlarge_x =
max(
min(def_width - this->
width, _screen.width - this->width), 0);
1531 int nx = this->
left;
1534 if (nx + this->
width > _screen.width) nx -= (nx + this->
width - _screen.width);
1537 ny =
max(ny, (wt == NULL ||
this == wt || this->
top == 0) ? 0 : wt->
height);
1564 int right = width + left;
1565 int bottom = height + top;
1567 if (left < 0 || top < toolbar_y || right > _screen.width || bottom > _screen.height)
return false;
1571 FOR_ALL_WINDOWS_FROM_BACK(w) {
1574 if (right > w->
left &&
1607 if (left < -(width >> 1) || left > _screen.width - (width >> 2))
return false;
1609 if (left < -(width >> 2) || left > _screen.width - (width >> 1))
return false;
1613 if (top < toolbar_y || top > _screen.height - (height >> 2))
return false;
1617 FOR_ALL_WINDOWS_FROM_BACK(w) {
1620 if (left + width > w->
left &&
1622 top + height > w->
top &&
1647 const int toolbar_y = main_toolbar != NULL ? main_toolbar->
height : 0;
1648 if (
IsGoodAutoPlace1(rtl ? _screen.width - width : 0, toolbar_y, width, height, toolbar_y, pt))
return pt;
1655 FOR_ALL_WINDOWS_FROM_BACK(w) {
1672 FOR_ALL_WINDOWS_FROM_BACK(w) {
1684 int left = rtl ? _screen.width - width : 0, top = toolbar_y;
1689 FOR_ALL_WINDOWS_FROM_BACK(w) {
1690 if (w->
left == left && w->
top == top) {
1744 pt.x = w->
left + (rtl ? w->
width - default_width : 0);
1753 if (w->
top + 3 * indent_y < _screen.height) {
1754 pt.y = w->
top + indent_y;
1758 pt.x =
max(w->
left + w->
width - default_width - indent_close, 0);
1759 if (pt.x + default_width >= indent_close && pt.x + indent_resize <= _screen.width)
return pt;
1761 pt.x =
min(w->
left + indent_close, _screen.width - default_width);
1762 if (pt.x + default_width >= indent_resize && pt.x + indent_close <= _screen.width)
return pt;
1776 pt.x = (_screen.width - default_width) / 2;
1777 pt.y = (_screen.height - default_height) / 2;
1806 int biggest_index = -1;
1857 FOR_ALL_WINDOWS_FROM_FRONT(w) {
1873 _z_back_window = NULL;
1874 _z_front_window = NULL;
1875 _focused_window = NULL;
1876 _mouseover_last_w = NULL;
1877 _last_scroll_window = NULL;
1882 NWidgetScrollbar::InvalidateDimensionCache();
1895 FOR_ALL_WINDOWS_FROM_FRONT(w)
delete w;
1897 for (w = _z_front_window; w != NULL; ) {
1903 _z_front_window = NULL;
1904 _z_back_window = NULL;
1917 static void DecreaseWindowCounters()
1920 FOR_ALL_WINDOWS_FROM_FRONT(w) {
1921 if (_scroller_click_timeout == 0) {
1938 it->second->HandleEditBox(w, it->first);
1944 FOR_ALL_WINDOWS_FROM_FRONT(w) {
1954 static void HandlePlacePresize()
1959 if (w == NULL)
return;
1961 Point pt = GetTileBelowCursor();
1984 pt.x = _cursor.
pos.x - w->
left;
1985 pt.y = _cursor.
pos.y - w->
top;
2003 if (_mouseover_last_w != NULL && _mouseover_last_w != w) {
2005 Point pt = { -1, -1 };
2010 _mouseover_last_w = w;
2041 if (v == NULL)
return;
2045 int safe_y = (dir ==
PHD_UP) ? (v->
top - MIN_VISIBLE_TITLE_BAR - rect.top) : (v_bottom + MIN_VISIBLE_TITLE_BAR - rect.bottom);
2047 if (*ny + rect.top <= v->
top - MIN_VISIBLE_TITLE_BAR)
return;
2048 if (*ny + rect.bottom >= v_bottom + MIN_VISIBLE_TITLE_BAR)
return;
2051 if (*nx + rect.left + MIN_VISIBLE_TITLE_BAR < v->left) {
2052 if (v->
left < MIN_VISIBLE_TITLE_BAR) *ny = safe_y;
2055 if (*nx + rect.right - MIN_VISIBLE_TITLE_BAR > v_right) {
2056 if (v_right > _screen.width - MIN_VISIBLE_TITLE_BAR) *ny = safe_y;
2061 if (px + rect.left < v->
left && v->
left >= MIN_VISIBLE_TITLE_BAR) {
2062 *nx = v->
left - MIN_VISIBLE_TITLE_BAR - rect.left;
2063 }
else if (px + rect.right > v_right && v_right <= _screen.width - MIN_VISIBLE_TITLE_BAR) {
2064 *nx = v_right + MIN_VISIBLE_TITLE_BAR - rect.right;
2082 if (caption != NULL) {
2083 caption_rect.left = caption->
pos_x;
2085 caption_rect.top = caption->
pos_y;
2089 nx =
Clamp(nx, MIN_VISIBLE_TITLE_BAR - caption_rect.right, _screen.width - MIN_VISIBLE_TITLE_BAR - caption_rect.left);
2090 ny =
Clamp(ny, 0, _screen.height - MIN_VISIBLE_TITLE_BAR);
2118 if (delta_x != 0 || delta_y != 0) {
2119 if (clamp_to_screen) {
2122 int new_right = w->
left + w->
width + delta_x;
2123 int new_bottom = w->
top + w->
height + delta_y;
2155 return (w == NULL) ? 0 : w->
top + w->
height;
2166 return (w == NULL) ? _screen.height : w->
top;
2185 FOR_ALL_WINDOWS_FROM_BACK(w) {
2195 int x = _cursor.
pos.x + _drag_delta.x;
2196 int y = _cursor.
pos.y + _drag_delta.y;
2207 FOR_ALL_WINDOWS_FROM_BACK(v) {
2208 if (v == w)
continue;
2213 if (delta <= hsnap) {
2220 if (delta <= hsnap) {
2229 if (delta <= hsnap) {
2236 if (delta <= hsnap) {
2245 if (delta <= vsnap) {
2252 if (delta <= vsnap) {
2261 if (delta <= vsnap) {
2268 if (delta <= vsnap) {
2291 int x, y = _cursor.
pos.y - _drag_delta.y;
2293 x = _drag_delta.x - _cursor.
pos.x;
2295 x = _cursor.
pos.x - _drag_delta.x;
2303 if (w->
top + w->
height + y > _screen.height) {
2304 y = _screen.height - w->
height - w->
top;
2341 _dragging_window =
false;
2353 _dragging_window =
true;
2355 _drag_delta.x = w->
left - _cursor.
pos.x;
2356 _drag_delta.y = w->
top - _cursor.
pos.y;
2371 _dragging_window =
true;
2373 _drag_delta.x = _cursor.
pos.x;
2374 _drag_delta.y = _cursor.
pos.y;
2387 FOR_ALL_WINDOWS_FROM_BACK(w) {
2401 i = _cursor.
pos.x - _cursorpos_drag_start.x;
2404 i = _cursor.
pos.y - _cursorpos_drag_start.y;
2408 if (_scroller_click_timeout == 1) {
2409 _scroller_click_timeout = 3;
2448 _last_scroll_window = NULL;
2461 delta.x = -_cursor.
delta.x;
2462 delta.y = -_cursor.
delta.y;
2464 delta.x = _cursor.
delta.x;
2465 delta.y = _cursor.
delta.y;
2468 if (scrollwheel_scrolling) {
2470 delta.x = _cursor.h_wheel;
2471 delta.y = _cursor.v_wheel;
2472 _cursor.v_wheel = 0;
2473 _cursor.h_wheel = 0;
2477 if (delta.x != 0 || delta.y != 0) _last_scroll_window->
OnScroll(delta);
2479 _cursor.
delta.x = 0;
2480 _cursor.
delta.y = 0;
2496 bool bring_to_front =
false;
2506 int w_width = w->
width;
2507 int w_height = w->
height;
2530 if (w->
left + w_width <= u->left ||
2532 w->
top + w_height <= u->top ||
2537 bring_to_front =
true;
2559 switch (query->text.HandleKeyPress(key, keycode)) {
2603 if (query->text.
bytes <= 1) {
2638 if (key >= 0xE000 && key <= 0xF8FF) key = 0;
2643 if (key == 0 && keycode == 0)
return;
2657 FOR_ALL_WINDOWS_FROM_FRONT(w) {
2676 HandleGlobalHotkeys(key, keycode);
2686 FOR_ALL_WINDOWS_FROM_FRONT(w) {
2696 void Window::InsertTextString(
int wid,
const char *str,
bool marked,
const char *caret,
const char *insert_location,
const char *replacement_end)
2699 if (query == NULL)
return;
2701 if (query->text.
InsertString(str, marked, caret, insert_location, replacement_end) || marked) {
2713 void HandleTextInput(
const char *str,
bool marked,
const char *caret,
const char *insert_location,
const char *replacement_end)
2738 int x = _cursor.
pos.x;
2739 int y = _cursor.
pos.y;
2745 if (vp == NULL)
return;
2751 #define scrollspeed 3
2754 }
else if (15 - (vp->
width - x) > 0) {
2759 }
else if (15 - (vp->
height - y) > 0) {
2778 static void ScrollMainViewport(
int x,
int y)
2780 if (_game_mode != GM_MENU) {
2817 static void HandleKeyScrolling()
2825 ScrollMainViewport(scrollamt[
_dirkeys][0] * factor, scrollamt[
_dirkeys][1] * factor);
2829 static void MouseLoop(
MouseClick click,
int mousewheel)
2835 HandlePlacePresize();
2847 if (click == MC_NONE && mousewheel == 0 && !scrollwheel_scrolling)
return;
2849 int x = _cursor.
pos.x;
2850 int y = _cursor.
pos.y;
2852 if (w == NULL)
return;
2860 if (mousewheel != 0) {
2869 if (scrollwheel_scrolling) click = MC_RIGHT;
2871 case MC_DOUBLE_LEFT:
2873 if (HandleViewportClicked(vp, x, y))
return;
2888 _cursor.h_wheel = 0;
2889 _cursor.v_wheel = 0;
2902 case MC_DOUBLE_LEFT:
2928 static int double_click_time = 0;
2929 static Point double_click_pos = {0, 0};
2938 click = MC_DOUBLE_LEFT;
2941 double_click_pos = _cursor.
pos;
2943 _input_events_this_tick++;
2947 _input_events_this_tick++;
2951 if (_cursor.
wheel) {
2952 mousewheel = _cursor.
wheel;
2954 _input_events_this_tick++;
2957 static uint32 hover_time = 0;
2958 static Point hover_pos = {0, 0};
2964 hover_pos = _cursor.
pos;
2970 _input_events_this_tick++;
2992 MouseLoop(click, mousewheel);
2997 _cursor.
delta.x = 0;
2998 _cursor.
delta.y = 0;
3009 uint deletable_count = 0;
3010 Window *w, *last_deletable = NULL;
3011 FOR_ALL_WINDOWS_FROM_FRONT(w) {
3021 assert(last_deletable != NULL);
3022 delete last_deletable;
3036 HandleKeyScrolling();
3039 for (
Window *v = _z_front_window; v != NULL; ) {
3049 if (_scroller_click_timeout != 0) _scroller_click_timeout--;
3050 DecreaseWindowCounters();
3052 if (_input_events_this_tick != 0) {
3054 _input_events_this_tick = 0;
3071 static int highlight_timer = 1;
3072 if (--highlight_timer == 0) {
3073 highlight_timer = 15;
3077 FOR_ALL_WINDOWS_FROM_FRONT(w) {
3086 static int we4_timer = 0;
3087 int t = we4_timer + 1;
3090 FOR_ALL_WINDOWS_FROM_FRONT(w) {
3097 FOR_ALL_WINDOWS_FROM_FRONT(w) {
3106 FOR_ALL_WINDOWS_FROM_BACK(w) {
3123 FOR_ALL_WINDOWS_FROM_BACK(w) {
3137 FOR_ALL_WINDOWS_FROM_BACK(w) {
3151 FOR_ALL_WINDOWS_FROM_BACK(w) {
3223 FOR_ALL_WINDOWS_FROM_BACK(w) {
3242 FOR_ALL_WINDOWS_FROM_BACK(w) {
3255 FOR_ALL_WINDOWS_FROM_FRONT(w) {
3274 FOR_ALL_WINDOWS_FROM_BACK(w) {
3283 goto restart_search;
3306 FOR_ALL_WINDOWS_FROM_BACK(w) {
3309 goto restart_search;
3326 FOR_ALL_WINDOWS_FROM_BACK(w) {
3329 goto restart_search;
3333 FOR_ALL_WINDOWS_FROM_BACK(w) w->
SetDirty();
3347 NWidgetScrollbar::InvalidateDimensionCache();
3353 FOR_ALL_WINDOWS_FROM_BACK(w) {
3356 #ifdef ENABLE_NETWORK
3378 if (w == NULL)
return 0;
3380 int old_left = w->
left;
3382 case 1: w->
left = (_screen.width - w->
width) / 2;
break;
3383 case 2: w->
left = _screen.width - w->
width;
break;
3384 default: w->
left = 0;
break;
3398 DEBUG(misc, 5,
"Repositioning Main Toolbar...");
3409 DEBUG(misc, 5,
"Repositioning statusbar...");
3420 DEBUG(misc, 5,
"Repositioning news message...");
3431 DEBUG(misc, 5,
"Repositioning network chat window...");
3444 FOR_ALL_WINDOWS_FROM_BACK(w) {
3462 FOR_ALL_WINDOWS_FROM_BACK(w) {
3504 top = (newh - w->
height) >> 1;
3505 left = (neww - w->
width) >> 1;
3510 if (left + (w->
width >> 1) >= neww) left = neww - w->
width;
3511 if (left < 0) left = 0;
3514 if (top + (w->
height >> 1) >= newh) top = newh - w->
height;