2005-07-24 16:12:37 +02:00
/* $Id$ */
2008-05-06 17:11:33 +02:00
/** @file window.cpp Windowing system, widgets and events */
2007-02-23 02:48:53 +01:00
2004-08-09 19:04:08 +02:00
# include "stdafx.h"
2006-10-06 23:10:14 +02:00
# include <stdarg.h>
2005-06-02 21:30:21 +02:00
# include "openttd.h"
2008-09-30 22:51:04 +02:00
# include "company_func.h"
2008-01-09 10:45:45 +01:00
# include "gfx_func.h"
2008-05-24 12:15:06 +02:00
# include "console_func.h"
# include "console_gui.h"
2008-01-09 10:45:45 +01:00
# include "viewport_func.h"
2005-07-22 00:15:02 +02:00
# include "variables.h"
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
# include "genworld.h"
2007-06-17 22:30:28 +02:00
# include "blitter/factory.hpp"
2007-12-23 11:56:02 +01:00
# include "zoom_func.h"
2007-12-26 12:45:43 +01:00
# include "map_func.h"
2007-12-27 14:35:39 +01:00
# include "vehicle_base.h"
2008-01-13 15:37:30 +01:00
# include "settings_type.h"
2009-01-31 21:16:06 +01:00
# include "cheat_type.h"
2008-05-07 00:17:12 +02:00
# include "window_func.h"
2008-05-07 15:10:15 +02:00
# include "tilehighlight_func.h"
2008-08-12 00:45:11 +02:00
# include "network/network.h"
2009-01-03 14:59:05 +01:00
# include "querystring_gui.h"
2009-02-01 23:32:07 +01:00
# include "widgets/dropdown_func.h"
2004-08-09 19:04:08 +02:00
2008-01-13 02:21:35 +01:00
# include "table/sprites.h"
2008-04-13 21:06:30 +02:00
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
2004-11-10 22:14:16 +01:00
2009-01-07 17:11:27 +01:00
/** List of windows opened at the screen sorted from the front. */
Window * _z_front_window = NULL ;
/** List of windows opened at the screen sorted from the back. */
Window * _z_back_window = NULL ;
2006-11-18 17:47:02 +01:00
2009-02-09 02:22:29 +01:00
/*
* Window that currently have focus . - The main purpose is to generate
* FocusLost events , not to give next window in z - order focus when a
* window is closed .
*/
Window * _focused_window ;
2008-01-13 14:36:01 +01:00
Point _cursorpos_drag_start ;
int _scrollbar_start_pos ;
int _scrollbar_size ;
byte _scroller_click_timeout ;
bool _scrolling_scrollbar ;
bool _scrolling_viewport ;
byte _special_mouse_mode ;
2009-03-15 16:12:06 +01:00
/** Window description constructor. */
WindowDesc : : WindowDesc ( int16 left , int16 top , int16 min_width , int16 min_height , int16 def_width , int16 def_height ,
2009-03-22 22:15:45 +01:00
WindowClass window_class , WindowClass parent_class , uint32 flags , const Widget * widgets ,
const NWidgetPart * nwid_parts , int16 nwid_length )
2009-03-15 16:12:06 +01:00
{
this - > left = left ;
this - > top = top ;
this - > minimum_width = min_width ;
this - > minimum_height = min_height ;
this - > default_width = def_width ;
this - > default_height = def_height ;
this - > cls = window_class ;
this - > parent_cls = parent_class ;
this - > flags = flags ;
this - > widgets = widgets ;
2009-03-22 22:15:45 +01:00
this - > nwid_parts = nwid_parts ;
this - > nwid_length = nwid_length ;
this - > new_widgets = NULL ;
2009-03-15 16:12:06 +01:00
}
2009-03-22 22:15:45 +01:00
/** Get widget array of the window description. */
const Widget * WindowDesc : : GetWidgets ( ) const
{
2009-05-04 20:40:37 +02:00
if ( this - > nwid_parts ! = NULL ) {
InitializeWidgetArrayFromNestedWidgets ( this - > nwid_parts , this - > nwid_length , this - > widgets , & this - > new_widgets ) ;
2009-03-22 22:15:45 +01:00
}
const Widget * wids = ( this - > new_widgets ! = NULL ) ? this - > new_widgets : this - > widgets ;
assert ( wids ! = NULL ) ;
return wids ;
}
WindowDesc : : ~ WindowDesc ( )
{
free ( this - > new_widgets ) ;
}
2009-03-15 16:12:06 +01:00
2009-02-09 02:22:29 +01:00
/**
* Set the window that has the focus
* @ param w The window to set the focus on
*/
void SetFocusedWindow ( Window * w )
{
if ( _focused_window = = w ) return ;
/* Invalidate focused widget */
2009-06-04 16:07:05 +02:00
if ( _focused_window ! = NULL ) {
if ( _focused_window - > focused_widget ! = NULL ) {
uint focused_widget_id = _focused_window - > focused_widget - _focused_window - > widget ;
_focused_window - > InvalidateWidget ( focused_widget_id ) ;
}
if ( _focused_window - > nested_focus ! = NULL ) _focused_window - > nested_focus - > Invalidate ( _focused_window ) ;
2009-02-09 02:22:29 +01:00
}
/* Remember which window was previously focused */
Window * old_focused = _focused_window ;
_focused_window = w ;
/* So we can inform it that it lost focus */
if ( old_focused ! = NULL ) old_focused - > OnFocusLost ( ) ;
if ( _focused_window ! = NULL ) _focused_window - > OnFocus ( ) ;
}
/**
* Check if an edit box is in global focus . That is if focused window
* has a edit box as focused widget , or if a console is focused .
* @ return returns true if an edit box is in global focus or if the focused window is a console , else false
*/
bool EditBoxInGlobalFocus ( )
{
2009-06-04 16:07:05 +02:00
if ( _focused_window = = NULL ) return false ;
2009-02-09 02:22:29 +01:00
/* The console does not have an edit box so a special case is needed. */
2009-06-04 16:07:05 +02:00
if ( _focused_window - > window_class = = WC_CONSOLE ) return true ;
if ( _focused_window - > nested_array ! = NULL ) {
return _focused_window - > nested_focus ! = NULL & & _focused_window - > nested_focus - > type = = WWT_EDITBOX ;
}
return _focused_window - > focused_widget ! = NULL & & _focused_window - > focused_widget - > type = = WWT_EDITBOX ;
2009-02-09 02:22:29 +01:00
}
2008-01-13 14:36:01 +01:00
2008-10-14 21:27:08 +02:00
/**
* Sets the enabled / disabled status of a list of widgets .
* By default , widgets are enabled .
* On certain conditions , they have to be disabled .
* @ param disab_stat status to use ie : disabled = true , enabled = false
* @ param widgets list of widgets ended by WIDGET_LIST_END
*/
2007-12-02 01:59:48 +01:00
void CDECL Window : : SetWidgetsDisabledState ( bool disab_stat , int widgets , . . . )
{
va_list wdg_list ;
va_start ( wdg_list , widgets ) ;
while ( widgets ! = WIDGET_LIST_END ) {
SetWidgetDisabledState ( widgets , disab_stat ) ;
widgets = va_arg ( wdg_list , int ) ;
}
va_end ( wdg_list ) ;
}
2008-10-14 21:27:08 +02:00
/**
* Sets the hidden / shown status of a list of widgets .
* By default , widgets are visible .
* On certain conditions , they have to be hidden .
* @ param hidden_stat status to use ie . hidden = true , visible = false
* @ param widgets list of widgets ended by WIDGET_LIST_END
*/
2007-12-02 01:59:48 +01:00
void CDECL Window : : SetWidgetsHiddenState ( bool hidden_stat , int widgets , . . . )
{
va_list wdg_list ;
va_start ( wdg_list , widgets ) ;
while ( widgets ! = WIDGET_LIST_END ) {
SetWidgetHiddenState ( widgets , hidden_stat ) ;
widgets = va_arg ( wdg_list , int ) ;
}
va_end ( wdg_list ) ;
}
2008-10-14 21:27:08 +02:00
/**
* Sets the lowered / raised status of a list of widgets .
* @ param lowered_stat status to use ie : lowered = true , raised = false
* @ param widgets list of widgets ended by WIDGET_LIST_END
*/
2007-12-02 01:59:48 +01:00
void CDECL Window : : SetWidgetsLoweredState ( bool lowered_stat , int widgets , . . . )
{
va_list wdg_list ;
va_start ( wdg_list , widgets ) ;
while ( widgets ! = WIDGET_LIST_END ) {
SetWidgetLoweredState ( widgets , lowered_stat ) ;
widgets = va_arg ( wdg_list , int ) ;
}
va_end ( wdg_list ) ;
}
2008-10-14 21:27:08 +02:00
/**
* Raise all buttons of the window
*/
2007-12-02 01:59:48 +01:00
void Window : : RaiseButtons ( )
{
2009-06-03 23:13:13 +02:00
if ( this - > widget ! = NULL ) {
for ( uint i = 0 ; i < this - > widget_count ; i + + ) {
if ( this - > IsWidgetLowered ( i ) ) {
this - > RaiseWidget ( i ) ;
this - > InvalidateWidget ( i ) ;
}
}
}
if ( this - > nested_array ! = NULL ) {
for ( uint i = 0 ; i < this - > nested_array_size ; i + + ) {
if ( this - > IsWidgetLowered ( i ) ) {
this - > RaiseWidget ( i ) ;
this - > InvalidateWidget ( i ) ;
}
2007-12-02 01:59:48 +01:00
}
}
}
2008-10-14 21:27:08 +02:00
/**
* Invalidate a widget , i . e . mark it as being changed and in need of redraw .
* @ param widget_index the widget to redraw .
*/
2007-12-07 18:42:15 +01:00
void Window : : InvalidateWidget ( byte widget_index ) const
2007-12-02 01:59:48 +01:00
{
2009-06-03 23:13:13 +02:00
if ( this - > widget ! = NULL ) {
const Widget * wi = & this - > widget [ widget_index ] ;
2007-12-02 01:59:48 +01:00
2009-06-03 23:13:13 +02:00
/* Don't redraw the window if the widget is invisible or of no-type */
if ( wi - > type = = WWT_EMPTY | | IsWidgetHidden ( widget_index ) ) return ;
2007-12-02 01:59:48 +01:00
2009-06-03 23:13:13 +02:00
SetDirtyBlocks ( this - > left + wi - > left , this - > top + wi - > top , this - > left + wi - > right + 1 , this - > top + wi - > bottom + 1 ) ;
}
if ( this - > nested_array ! = NULL ) this - > nested_array [ widget_index ] - > Invalidate ( this ) ;
2007-12-02 01:59:48 +01:00
}
2008-10-14 21:27:08 +02:00
/**
* Do all things to make a button look clicked and mark it to be
* unclicked in a few ticks .
* @ param widget the widget to " click "
*/
2007-12-08 03:55:47 +01:00
void Window : : HandleButtonClick ( byte widget )
{
this - > LowerWidget ( widget ) ;
2008-09-23 17:24:15 +02:00
this - > flags4 | = WF_TIMEOUT_BEGIN ;
2007-12-08 03:55:47 +01:00
this - > InvalidateWidget ( widget ) ;
}
2009-02-09 02:22:29 +01:00
/**
2009-05-16 13:25:19 +02:00
* Return a widget of the requested type from the window .
2009-02-09 02:22:29 +01:00
* @ param widget_type the widget type to look for
*/
2009-05-16 13:25:19 +02:00
const Widget * Window : : GetWidgetOfType ( WidgetType widget_type ) const
2009-02-09 02:22:29 +01:00
{
for ( uint i = 0 ; i < this - > widget_count ; i + + ) {
2009-05-16 13:25:19 +02:00
if ( this - > widget [ i ] . type = = widget_type ) return & this - > widget [ i ] ;
2009-02-09 02:22:29 +01:00
}
2009-05-16 13:25:19 +02:00
return NULL ;
2009-02-09 02:22:29 +01:00
}
2006-11-18 17:47:02 +01:00
static void StartWindowDrag ( Window * w ) ;
2009-03-18 02:06:48 +01:00
static void StartWindowSizing ( Window * w , bool to_left ) ;
2006-01-05 13:40:50 +01:00
2008-04-07 22:28:58 +02:00
/**
* Dispatch left mouse - button ( possibly double ) click in window .
* @ param w Window to dispatch event in
* @ param x X coordinate of the click
* @ param y Y coordinate of the click
* @ param double_click Was it a double click ?
*/
2007-06-22 12:57:53 +02:00
static void DispatchLeftClickEvent ( Window * w , int x , int y , bool double_click )
2005-11-04 15:01:44 +01:00
{
2009-05-31 16:30:58 +02:00
int widget_index = 0 ;
2004-08-09 19:04:08 +02:00
if ( w - > desc_flags & WDF_DEF_WIDGET ) {
2009-06-04 16:07:05 +02:00
const Widget * wi = NULL ;
const NWidgetCore * nw = NULL ;
WidgetType widget_type ;
if ( w - > widget ! = NULL ) {
widget_index = GetWidgetFromPos ( w , x , y ) ;
wi = & w - > widget [ widget_index ] ;
widget_type = ( widget_index > = 0 ) ? wi - > type : WWT_EMPTY ;
} else {
assert ( w - > nested_root ! = NULL ) ;
nw = w - > nested_root - > GetWidgetFromPos ( x , y ) ;
widget_index = ( nw ! = NULL ) ? nw - > index : - 1 ;
widget_type = ( widget_index > = 0 ) ? nw - > type : WWT_EMPTY ;
}
2009-02-09 02:22:29 +01:00
2009-05-30 14:41:53 +02:00
bool focused_widget_changed = false ;
2009-02-09 02:22:29 +01:00
/* If clicked on a window that previously did dot have focus */
if ( _focused_window ! = w & &
( w - > desc_flags & WDF_NO_FOCUS ) = = 0 & & // Don't lose focus to toolbars
2009-05-31 16:30:58 +02:00
! ( ( w - > desc_flags & WDF_STD_BTN ) & & widget_type = = WWT_CLOSEBOX ) ) { // Don't change focused window if 'X' (close button) was clicked
2009-02-09 02:22:29 +01:00
focused_widget_changed = true ;
if ( _focused_window ! = NULL ) {
_focused_window - > OnFocusLost ( ) ;
/* The window that lost focus may have had opened a OSK, window so close it, unless the user has clicked on the OSK window. */
if ( w - > window_class ! = WC_OSK ) DeleteWindowById ( WC_OSK , 0 ) ;
}
SetFocusedWindow ( w ) ;
w - > OnFocus ( ) ;
}
2009-05-31 16:30:58 +02:00
if ( widget_index < 0 ) return ; // exit if clicked outside of widgets
2004-09-05 16:20:36 +02:00
2004-09-12 16:12:33 +02:00
/* don't allow any interaction if the button has been disabled */
2009-05-31 16:30:58 +02:00
if ( w - > IsWidgetDisabled ( widget_index ) ) return ;
2006-12-04 14:57:04 +01:00
2009-02-09 02:22:29 +01:00
/* Clicked on a widget that is not disabled.
* So unless the clicked widget is the caption bar , change focus to this widget */
2009-05-31 16:30:58 +02:00
if ( widget_type ! = WWT_CAPTION ) {
2009-02-09 02:22:29 +01:00
/* Close the OSK window if a edit box loses focus */
2009-06-04 16:07:05 +02:00
if ( ( w - > widget ! = NULL & & w - > focused_widget ! = NULL & & w - > focused_widget - > type = = WWT_EDITBOX & & // An edit box was previously selected
w - > focused_widget ! = wi & & w - > window_class ! = WC_OSK ) | | // and focus is going to change and it is not the OSK window
( w - > nested_root ! = NULL & & w - > nested_focus ! = NULL & & w - > nested_focus - > type = = WWT_EDITBOX & &
w - > nested_focus ! = nw & & w - > window_class ! = WC_OSK ) ) {
2009-02-09 02:22:29 +01:00
DeleteWindowById ( WC_OSK , 0 ) ;
}
2009-05-31 16:30:58 +02:00
focused_widget_changed = w - > SetFocusedWidget ( widget_index ) ;
2009-02-09 02:22:29 +01:00
}
2009-05-31 16:30:58 +02:00
if ( widget_type & WWB_PUSHBUTTON ) {
2004-09-12 16:12:33 +02:00
/* special widget handling for buttons*/
2009-05-31 16:30:58 +02:00
switch ( widget_type ) {
2009-02-09 02:06:23 +01:00
default : NOT_REACHED ( ) ;
2009-03-15 01:32:18 +01:00
case WWT_PANEL | WWB_PUSHBUTTON : // WWT_PUSHBTN
case WWT_IMGBTN | WWB_PUSHBUTTON : // WWT_PUSHIMGBTN
case WWT_TEXTBTN | WWB_PUSHBUTTON : // WWT_PUSHTXTBTN
2009-05-31 16:30:58 +02:00
w - > HandleButtonClick ( widget_index ) ;
2006-10-24 16:15:17 +02:00
break ;
2004-08-09 19:04:08 +02:00
}
2009-05-31 16:30:58 +02:00
} else if ( widget_type = = WWT_SCROLLBAR | | widget_type = = WWT_SCROLL2BAR | | widget_type = = WWT_HSCROLLBAR ) {
2009-06-04 16:07:05 +02:00
if ( wi ! = NULL ) {
ScrollbarClickHandler ( w , wi , x , y ) ;
} else {
ScrollbarClickHandler ( w , nw , x , y ) ;
}
2009-05-31 16:30:58 +02:00
} else if ( widget_type = = WWT_EDITBOX & & ! focused_widget_changed ) { // Only open the OSK window if clicking on an already focused edit box
2009-01-03 14:59:05 +01:00
/* Open the OSK window if clicked on an edit box */
2009-05-31 16:30:58 +02:00
QueryStringBaseWindow * qs = dynamic_cast < QueryStringBaseWindow * > ( w ) ;
2009-01-03 14:59:05 +01:00
if ( qs ! = NULL ) {
qs - > OnOpenOSKWindow ( widget_index ) ;
}
2004-08-09 19:04:08 +02:00
}
2009-02-01 23:32:07 +01:00
/* Close any child drop down menus. If the button pressed was the drop down
* list ' s own button , then we should not process the click any further . */
2009-05-31 16:30:58 +02:00
if ( HideDropDownMenu ( w ) = = widget_index ) return ;
2009-02-01 23:32:07 +01:00
2004-08-09 19:04:08 +02:00
if ( w - > desc_flags & WDF_STD_BTN ) {
2009-05-31 16:30:58 +02:00
if ( widget_type = = WWT_CLOSEBOX ) { // 'X'
2008-05-06 23:28:30 +02:00
delete w ;
2005-01-11 13:15:08 +01:00
return ;
2005-01-23 14:09:35 +01:00
}
2009-05-31 16:30:58 +02:00
if ( widget_type = = WWT_CAPTION ) { // 'Title bar'
2006-11-18 17:47:02 +01:00
StartWindowDrag ( w ) ;
2005-01-23 14:42:26 +01:00
return ;
}
2004-08-09 19:04:08 +02:00
}
2005-01-03 20:45:18 +01:00
2009-06-01 13:43:36 +02:00
if ( ( w - > desc_flags & WDF_RESIZABLE ) & & widget_type = = WWT_RESIZEBOX ) {
2009-03-18 02:06:48 +01:00
/* When the resize widget is on the left size of the window
* we assume that that button is used to resize to the left . */
2009-06-04 16:07:05 +02:00
int left_pos = ( wi ! = NULL ) ? wi - > left : nw - > pos_x ;
StartWindowSizing ( w , left_pos < ( w - > width / 2 ) ) ;
2009-05-31 16:30:58 +02:00
w - > InvalidateWidget ( widget_index ) ;
2005-01-23 14:42:26 +01:00
return ;
}
2005-01-03 20:45:18 +01:00
2009-06-01 13:43:36 +02:00
if ( ( w - > desc_flags & WDF_STICKY_BUTTON ) & & widget_type = = WWT_STICKYBOX ) {
2005-01-03 20:45:18 +01:00
w - > flags4 ^ = WF_STICKY ;
2009-05-31 16:30:58 +02:00
w - > InvalidateWidget ( widget_index ) ;
2005-01-23 14:42:26 +01:00
return ;
2004-12-16 00:33:04 +01:00
}
2004-08-09 19:04:08 +02:00
}
2005-01-16 13:30:52 +01:00
2008-05-10 15:46:36 +02:00
Point pt = { x , y } ;
if ( double_click ) {
2009-05-31 16:30:58 +02:00
w - > OnDoubleClick ( pt , widget_index ) ;
2008-05-10 15:46:36 +02:00
} else {
2009-05-31 16:30:58 +02:00
w - > OnClick ( pt , widget_index ) ;
2008-05-10 15:46:36 +02:00
}
2004-08-09 19:04:08 +02:00
}
2008-04-07 22:28:58 +02:00
/**
* Dispatch right mouse - button click in window .
* @ param w Window to dispatch event in
* @ param x X coordinate of the click
* @ param y Y coordinate of the click
*/
2006-07-26 05:33:12 +02:00
static void DispatchRightClickEvent ( Window * w , int x , int y )
2005-11-04 15:01:44 +01:00
{
2008-05-10 15:46:36 +02:00
int widget = 0 ;
2009-06-04 16:07:05 +02:00
StringID tooltip = 0 ;
2004-08-09 19:04:08 +02:00
/* default tooltips handler? */
if ( w - > desc_flags & WDF_STD_TOOLTIPS ) {
2009-06-04 16:07:05 +02:00
if ( w - > nested_root ! = NULL ) {
NWidgetCore * wid = w - > nested_root - > GetWidgetFromPos ( x , y ) ;
if ( wid = = NULL | | wid - > index < 0 ) return ;
widget = wid - > index ;
tooltip = wid - > tool_tip ;
}
if ( w - > widget ! = NULL ) {
widget = GetWidgetFromPos ( w , x , y ) ;
if ( widget < 0 ) return ; // exit if clicked outside of widgets
tooltip = w - > widget [ widget ] . tooltips ;
}
2004-08-09 19:04:08 +02:00
2009-06-04 16:07:05 +02:00
if ( tooltip ! = 0 ) {
GuiShowTooltips ( tooltip ) ;
2004-08-09 19:04:08 +02:00
return ;
}
}
2008-05-10 15:46:36 +02:00
Point pt = { x , y } ;
w - > OnRightClick ( pt , widget ) ;
2004-08-09 19:04:08 +02:00
}
2008-04-07 22:28:58 +02:00
/**
* Dispatch the mousewheel - action to the window .
* The window will scroll any compatible scrollbars if the mouse is pointed over the bar or its contents
* @ param w Window
2005-07-08 02:14:19 +02:00
* @ param widget the widget where the scrollwheel was used
* @ param wheel scroll up or down
*/
2006-07-26 05:33:12 +02:00
static void DispatchMouseWheelEvent ( Window * w , int widget , int wheel )
2004-08-09 19:04:08 +02:00
{
2005-07-08 02:14:19 +02:00
if ( widget < 0 ) return ;
2009-06-04 14:46:37 +02:00
Scrollbar * sb = NULL ;
if ( w - > widget ! = NULL ) {
const Widget * wi1 = & w - > widget [ widget ] ;
const Widget * wi2 = & w - > widget [ widget + 1 ] ;
if ( wi1 - > type = = WWT_SCROLLBAR | | wi2 - > type = = WWT_SCROLLBAR ) {
sb = & w - > vscroll ;
} else if ( wi1 - > type = = WWT_SCROLL2BAR | | wi2 - > type = = WWT_SCROLL2BAR ) {
sb = & w - > vscroll2 ;
}
}
if ( w - > nested_array ! = NULL & & ( uint ) widget < w - > nested_array_size ) sb = w - > nested_array [ widget ] - > FindScrollbar ( w ) ;
if ( sb ! = NULL & & sb - > count > sb - > cap ) {
int pos = Clamp ( sb - > pos + wheel , 0 , sb - > count - sb - > cap ) ;
if ( pos ! = sb - > pos ) {
sb - > pos = pos ;
w - > SetDirty ( ) ;
2004-08-09 19:04:08 +02:00
}
}
}
2008-04-07 22:28:58 +02:00
/**
2009-01-07 17:11:27 +01:00
* Generate repaint events for the visible part of window w within the rectangle .
2008-04-07 22:28:58 +02:00
*
* The function goes recursively upwards in the window stack , and splits the rectangle
* into multiple pieces at the window edges , so obscured parts are not redrawn .
*
2009-01-07 17:11:27 +01:00
* @ param w Window that needs to be repainted
2008-04-07 22:28:58 +02:00
* @ param left Left edge of the rectangle that should be repainted
* @ param top Top edge of the rectangle that should be repainted
* @ param right Right edge of the rectangle that should be repainted
* @ param bottom Bottom edge of the rectangle that should be repainted
*/
2009-01-07 17:11:27 +01:00
static void DrawOverlappedWindow ( Window * w , int left , int top , int right , int bottom )
2004-08-09 19:04:08 +02:00
{
2009-01-07 19:59:46 +01:00
const Window * v ;
FOR_ALL_WINDOWS_FROM_BACK_FROM ( v , w - > z_front ) {
2004-08-09 19:04:08 +02:00
if ( right > v - > left & &
2005-07-09 00:25:24 +02:00
bottom > v - > top & &
2004-08-09 19:04:08 +02:00
left < v - > left + v - > width & &
top < v - > top + v - > height ) {
2008-04-07 22:28:58 +02:00
/* v and rectangle intersect with eeach other */
int x ;
2007-04-19 00:10:36 +02:00
if ( left < ( x = v - > left ) ) {
2009-01-07 17:11:27 +01:00
DrawOverlappedWindow ( w , left , top , x , bottom ) ;
DrawOverlappedWindow ( w , x , top , right , bottom ) ;
2004-08-09 19:04:08 +02:00
return ;
}
2007-04-19 00:10:36 +02:00
if ( right > ( x = v - > left + v - > width ) ) {
2009-01-07 17:11:27 +01:00
DrawOverlappedWindow ( w , left , top , x , bottom ) ;
DrawOverlappedWindow ( w , x , top , right , bottom ) ;
2004-08-09 19:04:08 +02:00
return ;
}
2007-04-19 00:10:36 +02:00
if ( top < ( x = v - > top ) ) {
2009-01-07 17:11:27 +01:00
DrawOverlappedWindow ( w , left , top , right , x ) ;
DrawOverlappedWindow ( w , left , x , right , bottom ) ;
2004-08-09 19:04:08 +02:00
return ;
}
2007-04-19 00:10:36 +02:00
if ( bottom > ( x = v - > top + v - > height ) ) {
2009-01-07 17:11:27 +01:00
DrawOverlappedWindow ( w , left , top , right , x ) ;
DrawOverlappedWindow ( w , left , x , right , bottom ) ;
2004-08-09 19:04:08 +02:00
return ;
}
return ;
}
}
2008-04-19 15:05:05 +02:00
/* Setup blitter, and dispatch a repaint event to window *wz */
2008-04-13 20:59:32 +02:00
DrawPixelInfo * dp = _cur_dpi ;
dp - > width = right - left ;
dp - > height = bottom - top ;
2009-01-07 17:11:27 +01:00
dp - > left = left - w - > left ;
dp - > top = top - w - > top ;
2008-04-13 20:59:32 +02:00
dp - > pitch = _screen . pitch ;
dp - > dst_ptr = BlitterFactoryBase : : GetCurrentBlitter ( ) - > MoveTo ( _screen . dst_ptr , left , top ) ;
dp - > zoom = ZOOM_LVL_NORMAL ;
2009-01-07 17:11:27 +01:00
w - > OnPaint ( ) ;
2008-04-13 20:59:32 +02:00
}
/**
* From a rectangle that needs redrawing , find the windows that intersect with the rectangle .
* These windows should be re - painted .
* @ param left Left edge of the rectangle that should be repainted
* @ param top Top edge of the rectangle that should be repainted
* @ param right Right edge of the rectangle that should be repainted
* @ param bottom Bottom edge of the rectangle that should be repainted
*/
void DrawOverlappedWindowForAll ( int left , int top , int right , int bottom )
{
2009-01-07 17:11:27 +01:00
Window * w ;
2008-04-13 20:59:32 +02:00
DrawPixelInfo bk ;
_cur_dpi = & bk ;
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2008-04-13 20:59:32 +02:00
if ( right > w - > left & &
bottom > w - > top & &
left < w - > left + w - > width & &
top < w - > top + w - > height ) {
2008-04-19 15:05:05 +02:00
/* Window w intersects with the rectangle => needs repaint */
2009-01-07 17:11:27 +01:00
DrawOverlappedWindow ( w , left , top , right , bottom ) ;
2008-04-13 20:59:32 +02:00
}
2004-08-09 19:04:08 +02:00
}
}
2008-05-06 23:28:30 +02:00
/**
* Mark entire window as dirty ( in need of re - paint )
* @ ingroup dirty
*/
void Window : : SetDirty ( ) const
{
SetDirtyBlocks ( this - > left , this - > top , this - > left + this - > width , this - > top + this - > height ) ;
}
2008-04-07 22:28:58 +02:00
/**
* Mark entire window as dirty ( in need of re - paint )
* @ param w Window to redraw
* @ ingroup dirty
*/
2006-07-26 05:33:12 +02:00
void SetWindowDirty ( const Window * w )
2004-08-09 19:04:08 +02:00
{
2008-05-06 23:28:30 +02:00
if ( w ! = NULL ) w - > SetDirty ( ) ;
2004-08-09 19:04:08 +02:00
}
2009-06-28 22:09:40 +02:00
/** Re-initialize a window.
* @ todo Extend the function to handle viewports .
*/
void Window : : ReInit ( )
{
if ( this - > nested_root = = NULL ) return ; // Only nested widget windows can re-initialize.
this - > SetDirty ( ) ; // Mark whole current window as dirty.
/* Save current size. */
int window_width = this - > width ;
int window_height = this - > height ;
/* Re-initialize the window from the ground up. No need to change the nested_array, as all widgets stay where they are. */
2009-07-04 17:35:36 +02:00
this - > nested_root - > SetupSmallestSize ( this ) ;
2009-06-28 22:09:40 +02:00
this - > nested_root - > AssignSizePosition ( ST_SMALLEST , 0 , 0 , this - > nested_root - > smallest_x , this - > nested_root - > smallest_y , false , false , false ) ;
this - > width = this - > nested_root - > smallest_x ;
this - > height = this - > nested_root - > smallest_y ;
this - > resize . width = this - > nested_root - > smallest_x ;
this - > resize . height = this - > nested_root - > smallest_y ;
this - > resize . step_width = this - > nested_root - > resize_x ;
this - > resize . step_height = this - > nested_root - > resize_y ;
/* Resize as close to the original size as possible. */
window_width = max ( window_width , this - > width ) ;
window_height = max ( window_height , this - > height ) ;
int dx = ( this - > resize . step_width = = 0 ) ? 0 : window_width - this - > width ;
int dy = ( this - > resize . step_height = = 0 ) ? 0 : window_height - this - > height ;
/* dx and dy has to go by step.. calculate it.
* The cast to int is necessary else dx / dy are implicitly casted to unsigned int , which won ' t work . */
if ( this - > resize . step_width > 1 ) dx - = dx % ( int ) this - > resize . step_width ;
if ( this - > resize . step_height > 1 ) dy - = dy % ( int ) this - > resize . step_height ;
2009-07-05 16:26:29 +02:00
if ( dx = = 0 & & dy = = 0 ) { // No resize needed.
this - > SetDirty ( ) ;
return ;
}
2009-06-28 22:09:40 +02:00
ResizeWindow ( this , dx , dy ) ; // Sets post-resize dirty blocks.
Point diff ;
diff . x = dx ;
diff . y = dy ;
this - > OnResize ( diff ) ;
}
2006-12-29 18:07:41 +01:00
/** Find the Window whose parent pointer points to this window
2007-04-09 17:06:24 +02:00
* @ param w parent Window to find child of
* @ return a Window pointer that is the child of w , or NULL otherwise */
2006-12-29 18:07:41 +01:00
static Window * FindChildWindow ( const Window * w )
{
2009-01-06 23:37:42 +01:00
Window * v ;
FOR_ALL_WINDOWS_FROM_BACK ( v ) {
2006-12-29 18:07:41 +01:00
if ( v - > parent = = w ) return v ;
}
return NULL ;
}
2008-09-24 18:40:06 +02:00
/**
* Delete all children a window might have in a head - recursive manner
*/
void Window : : DeleteChildWindows ( ) const
{
Window * child = FindChildWindow ( this ) ;
while ( child ! = NULL ) {
delete child ;
child = FindChildWindow ( this ) ;
}
}
2008-04-07 22:28:58 +02:00
/**
2008-04-19 15:05:05 +02:00
* Remove window and all its child windows from the window stack .
2008-04-07 22:28:58 +02:00
*/
2008-05-06 23:28:30 +02:00
Window : : ~ Window ( )
2006-11-18 17:47:02 +01:00
{
2009-04-19 12:31:30 +02:00
if ( _thd . place_mode ! = HT_NONE & &
2008-05-06 23:28:30 +02:00
_thd . window_class = = this - > window_class & &
_thd . window_number = = this - > window_number ) {
2004-08-09 19:04:08 +02:00
ResetObjectToPlace ( ) ;
}
2008-04-13 21:06:30 +02:00
/* Prevent Mouseover() from resetting mouse-over coordinates on a non-existing window */
2008-05-06 23:28:30 +02:00
if ( _mouseover_last_w = = this ) _mouseover_last_w = NULL ;
2008-04-13 21:06:30 +02:00
2009-06-01 15:28:05 +02:00
/* Make sure we don't try to access this window as the focused window when it doesn't exist anymore. */
2009-02-09 02:22:29 +01:00
if ( _focused_window = = this ) _focused_window = NULL ;
2008-09-24 18:40:06 +02:00
this - > DeleteChildWindows ( ) ;
2008-05-04 23:36:37 +02:00
2008-05-06 23:28:30 +02:00
if ( this - > viewport ! = NULL ) DeleteWindowViewport ( this ) ;
2008-05-04 23:36:37 +02:00
2008-05-06 23:28:30 +02:00
this - > SetDirty ( ) ;
2008-12-16 18:58:27 +01:00
2009-02-09 02:22:29 +01:00
free ( this - > widget ) ;
2009-06-03 22:00:33 +02:00
free ( this - > nested_array ) ; // Contents is released through deletion of #nested_root.
delete this - > nested_root ;
2009-01-07 19:59:46 +01:00
this - > window_class = WC_INVALID ;
2004-08-09 19:04:08 +02:00
}
2008-04-07 22:28:58 +02:00
/**
* Find a window by its class and window number
* @ param cls Window class
* @ param number Number of the window within the window class
* @ return Pointer to the found window , or \ c NULL if not available
*/
2004-08-09 19:04:08 +02:00
Window * FindWindowById ( WindowClass cls , WindowNumber number )
{
2009-01-06 23:37:42 +01:00
Window * w ;
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2005-11-14 20:48:04 +01:00
if ( w - > window_class = = cls & & w - > window_number = = number ) return w ;
2004-09-05 16:20:36 +02:00
}
2004-08-09 19:04:08 +02:00
return NULL ;
}
2008-04-07 22:28:58 +02:00
/**
* Delete a window by its class and window number ( if it is open ) .
* @ param cls Window class
* @ param number Number of the window within the window class
2009-01-02 21:59:04 +01:00
* @ param force force deletion ; if false don ' t delete when stickied
2008-04-07 22:28:58 +02:00
*/
2009-01-02 21:59:04 +01:00
void DeleteWindowById ( WindowClass cls , WindowNumber number , bool force )
2004-08-09 19:04:08 +02:00
{
2009-01-02 21:59:04 +01:00
Window * w = FindWindowById ( cls , number ) ;
if ( force | | w = = NULL | |
( w - > desc_flags & WDF_STICKY_BUTTON ) = = 0 | |
( w - > flags4 & WF_STICKY ) = = 0 ) {
delete w ;
}
2004-09-05 16:20:36 +02:00
}
2004-08-09 19:04:08 +02:00
2008-04-07 22:28:58 +02:00
/**
* Delete all windows of a given class
* @ param cls Window class of windows to delete
*/
2005-01-13 17:50:20 +01:00
void DeleteWindowByClass ( WindowClass cls )
{
2009-01-06 23:37:42 +01:00
Window * w ;
2005-11-14 20:48:04 +01:00
2006-11-18 01:44:09 +01:00
restart_search :
/* When we find the window to delete, we need to restart the search
2006-11-18 17:47:02 +01:00
* as deleting this window could cascade in deleting ( many ) others
* anywhere in the z - array */
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2005-01-13 17:50:20 +01:00
if ( w - > window_class = = cls ) {
2008-05-06 23:28:30 +02:00
delete w ;
2006-11-18 01:44:09 +01:00
goto restart_search ;
2005-11-14 20:48:04 +01:00
}
2005-01-13 17:50:20 +01:00
}
}
2008-09-30 22:39:50 +02:00
/** Delete all windows of a company. We identify windows of a company
* by looking at the caption colour . If it is equal to the company ID
* then we say the window belongs to the company and should be deleted
* @ param id company identifier */
void DeleteCompanyWindows ( CompanyID id )
2006-11-13 21:33:51 +01:00
{
2009-01-06 23:37:42 +01:00
Window * w ;
2006-11-13 21:33:51 +01:00
2006-11-18 01:44:09 +01:00
restart_search :
/* When we find the window to delete, we need to restart the search
2006-11-18 17:47:02 +01:00
* as deleting this window could cascade in deleting ( many ) others
* anywhere in the z - array */
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2009-02-09 03:33:10 +01:00
if ( w - > owner = = id ) {
2008-05-06 23:28:30 +02:00
delete w ;
2006-11-18 01:44:09 +01:00
goto restart_search ;
2006-11-13 21:33:51 +01:00
}
}
2008-09-30 22:39:50 +02:00
/* Also delete the company specific windows, that don't have a company-colour */
2006-11-18 01:14:43 +01:00
DeleteWindowById ( WC_BUY_COMPANY , id ) ;
2006-11-13 21:33:51 +01:00
}
2008-09-30 22:39:50 +02:00
/** Change the owner of all the windows one company can take over from another
* company in the case of a company merger . Do not change ownership of windows
2006-11-18 01:14:43 +01:00
* that need to be deleted once takeover is complete
2008-09-30 22:39:50 +02:00
* @ param old_owner original owner of the window
* @ param new_owner the new owner of the window */
void ChangeWindowOwner ( Owner old_owner , Owner new_owner )
2006-11-13 21:33:51 +01:00
{
2009-01-06 23:37:42 +01:00
Window * w ;
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2009-02-09 03:33:10 +01:00
if ( w - > owner ! = old_owner ) continue ;
2008-05-07 10:27:55 +02:00
switch ( w - > window_class ) {
2009-02-09 03:57:15 +01:00
case WC_COMPANY_COLOUR :
2008-05-07 10:27:55 +02:00
case WC_FINANCES :
case WC_STATION_LIST :
case WC_TRAINS_LIST :
case WC_ROADVEH_LIST :
case WC_SHIPS_LIST :
case WC_AIRCRAFT_LIST :
case WC_BUY_COMPANY :
case WC_COMPANY :
continue ;
default :
2009-02-09 03:33:10 +01:00
w - > owner = new_owner ;
2008-05-07 10:27:55 +02:00
break ;
}
2006-11-13 21:33:51 +01:00
}
}
2009-01-07 17:11:27 +01:00
static void BringWindowToFront ( Window * w ) ;
2006-01-05 13:40:50 +01:00
2006-11-18 17:47:02 +01:00
/** Find a window and make it the top-window on the screen. The window
2007-04-09 17:06:24 +02:00
* gets a white border for a brief period of time to visualize its " activation "
* @ param cls WindowClass of the window to activate
* @ param number WindowNumber of the window to activate
2006-11-18 17:47:02 +01:00
* @ return a pointer to the window thus activated */
2004-08-09 19:04:08 +02:00
Window * BringWindowToFrontById ( WindowClass cls , WindowNumber number )
{
Window * w = FindWindowById ( cls , number ) ;
if ( w ! = NULL ) {
w - > flags4 | = WF_WHITE_BORDER_MASK ;
2006-11-18 17:47:02 +01:00
BringWindowToFront ( w ) ;
2008-05-07 00:08:18 +02:00
w - > SetDirty ( ) ;
2004-08-09 19:04:08 +02:00
}
return w ;
}
2005-04-05 23:03:30 +02:00
static inline bool IsVitalWindow ( const Window * w )
{
2008-05-07 10:27:55 +02:00
switch ( w - > window_class ) {
case WC_MAIN_TOOLBAR :
case WC_STATUS_BAR :
case WC_NEWS_WINDOW :
case WC_SEND_NETWORK_MSG :
return true ;
default :
return false ;
}
2005-04-05 23:03:30 +02:00
}
/** On clicking on a window, make it the frontmost window of all. However
* there are certain windows that always need to be on - top ; these include
* - Toolbar , Statusbar ( always on )
* - New window , Chatbar ( only if open )
2006-11-18 01:14:43 +01:00
* The window is marked dirty for a repaint if the window is actually moved
2005-04-05 23:03:30 +02:00
* @ param w window that is put into the foreground
2006-11-18 17:47:02 +01:00
* @ return pointer to the window , the same as the input pointer
2005-04-05 23:03:30 +02:00
*/
2009-01-07 17:11:27 +01:00
static void BringWindowToFront ( Window * w )
2004-08-09 19:04:08 +02:00
{
2009-01-07 17:11:27 +01:00
Window * v = _z_front_window ;
2004-08-09 19:04:08 +02:00
2006-11-18 17:47:02 +01:00
/* Bring the window just below the vital windows */
2009-01-07 17:11:27 +01:00
for ( ; v ! = NULL & & v ! = w & & IsVitalWindow ( v ) ; v = v - > z_back ) { }
2004-08-09 19:04:08 +02:00
2009-01-07 17:11:27 +01:00
if ( v = = NULL | | w = = v ) return ; // window is already in the right position
2004-08-09 19:04:08 +02:00
2009-01-07 17:11:27 +01:00
/* w cannot be at the top already! */
assert ( w ! = _z_front_window ) ;
2004-08-09 19:04:08 +02:00
2009-01-07 17:11:27 +01:00
if ( w - > z_back = = NULL ) {
_z_back_window = w - > z_front ;
} else {
w - > z_back - > z_front = w - > z_front ;
2004-12-22 18:37:21 +01:00
}
2009-01-07 17:11:27 +01:00
w - > z_front - > z_back = w - > z_back ;
2004-12-22 18:37:21 +01:00
2009-01-07 17:11:27 +01:00
w - > z_front = v - > z_front ;
w - > z_back = v ;
if ( v - > z_front = = NULL ) {
_z_front_window = w ;
} else {
v - > z_front - > z_back = w ;
2004-12-22 18:37:21 +01:00
}
2009-01-07 17:11:27 +01:00
v - > z_front = w ;
w - > SetDirty ( ) ;
2004-12-22 18:37:21 +01:00
}
2008-05-10 15:53:11 +02:00
/**
* Assign widgets to a new window by initialising its widget pointers , and by
* copying the widget array \ a widget to \ c w - > widget to allow for resizable
* windows .
2007-04-09 17:06:24 +02:00
* @ param w Window on which to attach the widget array
2008-05-10 15:53:11 +02:00
* @ param widget pointer of widget array to fill the window with
*
* @ post \ c w - > widget points to allocated memory and contains the copied widget array except for the terminating widget ,
* \ c w - > widget_count contains number of widgets in the allocated memory .
*/
2008-05-10 15:54:20 +02:00
static void AssignWidgetToWindow ( Window * w , const Widget * widget )
2005-01-03 20:45:18 +01:00
{
if ( widget ! = NULL ) {
uint index = 1 ;
2005-11-14 20:48:04 +01:00
2008-05-07 10:27:55 +02:00
for ( const Widget * wi = widget ; wi - > type ! = WWT_LAST ; wi + + ) index + + ;
2005-01-03 20:45:18 +01:00
2008-05-10 15:53:11 +02:00
w - > widget = MallocT < Widget > ( index ) ;
2005-11-14 20:48:04 +01:00
memcpy ( w - > widget , widget , sizeof ( * w - > widget ) * index ) ;
2006-12-04 14:36:27 +01:00
w - > widget_count = index - 1 ;
2005-11-14 20:48:04 +01:00
} else {
2005-01-03 20:45:18 +01:00
w - > widget = NULL ;
2006-12-04 14:36:27 +01:00
w - > widget_count = 0 ;
2005-11-14 20:48:04 +01:00
}
2005-01-03 20:45:18 +01:00
}
2008-05-08 13:31:41 +02:00
/**
* Initializes a new Window .
* This function is called the constructors .
2006-09-02 22:09:16 +02:00
* See descriptions for those functions for usage
* Only addition here is window_number , which is the window_number being assigned to the new window
2009-06-04 16:34:38 +02:00
* @ param x Offset in pixels from the left of the screen of the new window .
* @ param y Offset in pixels from the top of the screen of the new window .
* @ param min_width Minimum width in pixels of the window
* @ param min_height Minimum height in pixels of the window
* @ param cls Class of the window , used for identification and grouping . @ see WindowClass
* @ param * widget Pointer to the window layout and various elements . @ see Widget
* @ param nested_root Root of the nested widget tree .
* @ param window_number Number being assigned to the new window
2008-05-13 16:43:33 +02:00
* @ return Window pointer of the newly created window
*/
2008-05-11 13:41:18 +02:00
void Window : : Initialize ( int x , int y , int min_width , int min_height ,
2009-06-04 16:34:38 +02:00
WindowClass cls , const Widget * widget , NWidgetBase * nested_root , int window_number )
2004-08-09 19:04:08 +02:00
{
2009-06-04 16:34:38 +02:00
/* If available, initialize nested widget tree. */
if ( nested_root ! = NULL ) {
this - > nested_root = nested_root ;
/* Setup nested_array pointers into the tree. */
2009-07-04 17:35:36 +02:00
int biggest_index = this - > nested_root - > SetupSmallestSize ( this ) ;
2009-06-04 16:34:38 +02:00
this - > nested_array_size = ( uint ) ( biggest_index + 1 ) ;
this - > nested_array = CallocT < NWidgetCore * > ( this - > nested_array_size ) ;
this - > nested_root - > FillNestedArray ( this - > nested_array , this - > nested_array_size ) ;
/* Initialize to smallest size. */
this - > nested_root - > AssignSizePosition ( ST_SMALLEST , 0 , 0 , this - > nested_root - > smallest_x , this - > nested_root - > smallest_y , false , false , false ) ;
min_width = this - > nested_root - > smallest_x ;
min_height = this - > nested_root - > smallest_y ;
}
/* Else, all data members of nested widgets have been set to 0 by the #ZeroedMemoryAllocator base class. */
2009-06-03 22:00:33 +02:00
2007-04-06 06:10:19 +02:00
/* Set up window properties */
2008-05-08 13:31:41 +02:00
this - > window_class = cls ;
this - > flags4 = WF_WHITE_BORDER_MASK ; // just opened windows have a white border
2009-02-09 03:33:10 +01:00
this - > owner = INVALID_OWNER ;
2008-05-08 13:31:41 +02:00
this - > left = x ;
this - > top = y ;
this - > width = min_width ;
this - > height = min_height ;
AssignWidgetToWindow ( this , widget ) ;
2009-05-30 13:01:05 +02:00
this - > focused_widget = NULL ;
2009-06-04 16:07:05 +02:00
this - > nested_focus = NULL ;
2008-05-08 13:31:41 +02:00
this - > resize . width = min_width ;
this - > resize . height = min_height ;
2009-06-04 16:34:38 +02:00
this - > resize . step_width = ( this - > nested_root ! = NULL ) ? this - > nested_root - > resize_x : 1 ;
this - > resize . step_height = ( this - > nested_root ! = NULL ) ? this - > nested_root - > resize_y : 1 ;
2008-05-08 13:31:41 +02:00
this - > window_number = window_number ;
2009-02-09 02:22:29 +01:00
/* Give focus to the opened window unless it is the OSK window or a text box
* of focused window has focus ( so we don ' t interrupt typing ) . But if the new
* window has a text box , then take focus anyway . */
2009-06-04 16:07:05 +02:00
bool has_editbox = ( this - > widget ! = NULL & & this - > GetWidgetOfType ( WWT_EDITBOX ) ! = NULL ) | |
( this - > nested_root ! = NULL & & this - > nested_root - > GetWidgetOfType ( WWT_EDITBOX ) ! = NULL ) ;
if ( this - > window_class ! = WC_OSK & & ( ! EditBoxInGlobalFocus ( ) | | has_editbox ) ) SetFocusedWindow ( this ) ;
2009-02-09 02:22:29 +01:00
2008-05-08 13:31:41 +02:00
/* Hacky way of specifying always-on-top windows. These windows are
2009-03-14 19:16:29 +01:00
* always above other windows because they are moved below them .
* status - bar is above news - window because it has been created earlier .
* Also , as the chat - window is excluded from this , it will always be
* the last window , thus always on top .
* XXX - Yes , ugly , probably needs something like w - > always_on_top flag
* to implement correctly , but even then you need some kind of distinction
* between on - top of chat / news and status windows , because these conflict */
2009-01-07 17:11:27 +01:00
Window * w = _z_front_window ;
if ( w ! = NULL & & this - > window_class ! = WC_SEND_NETWORK_MSG & & this - > window_class ! = WC_HIGHSCORE & & this - > window_class ! = WC_ENDSCREEN ) {
if ( FindWindowById ( WC_MAIN_TOOLBAR , 0 ) ! = NULL ) w = w - > z_back ;
if ( FindWindowById ( WC_STATUS_BAR , 0 ) ! = NULL ) w = w - > z_back ;
if ( FindWindowById ( WC_NEWS_WINDOW , 0 ) ! = NULL ) w = w - > z_back ;
if ( FindWindowById ( WC_SEND_NETWORK_MSG , 0 ) ! = NULL ) w = w - > z_back ;
if ( w = = NULL ) {
_z_back_window - > z_front = this ;
this - > z_back = _z_back_window ;
_z_back_window = this ;
} else {
if ( w - > z_front = = NULL ) {
_z_front_window = this ;
} else {
this - > z_front = w - > z_front ;
w - > z_front - > z_back = this ;
}
2008-05-08 13:31:41 +02:00
2009-01-07 17:11:27 +01:00
this - > z_back = w ;
w - > z_front = this ;
}
} else {
this - > z_back = _z_front_window ;
if ( _z_front_window ! = NULL ) {
_z_front_window - > z_front = this ;
} else {
_z_back_window = this ;
}
_z_front_window = this ;
2006-11-18 17:47:02 +01:00
}
2008-05-11 13:41:18 +02:00
}
2007-07-27 14:49:04 +02:00
2008-05-11 13:41:18 +02:00
/**
2008-05-30 00:22:02 +02:00
* Resize window towards the default size .
* Prior to construction , a position for the new window ( for its default size )
* has been found with LocalGetWindowPlacement ( ) . Initially , the window is
* constructed with minimal size . Resizing the window to its default size is
* done here .
2008-05-11 13:41:18 +02:00
* @ param def_width default width in pixels of the window
* @ param def_height default height in pixels of the window
2008-05-30 00:22:02 +02:00
* @ see Window : : Window ( ) , Window : : Initialize ( )
2008-05-11 13:41:18 +02:00
*/
void Window : : FindWindowPlacementAndResize ( int def_width , int def_height )
{
2009-06-04 16:34:38 +02:00
def_width = max ( def_width , this - > width ) ; // Don't allow default size to be smaller than smallest size
def_height = max ( def_height , this - > height ) ;
2007-07-28 22:59:30 +02:00
/* Try to make windows smaller when our window is too small.
* w - > ( width | height ) is normally the same as min_ ( width | height ) ,
* but this way the GUIs can be made a little more dynamic ;
* one can use the same spec for multiple windows and those
* can then determine the real minimum size of the window . */
2008-05-08 13:31:41 +02:00
if ( this - > width ! = def_width | | this - > height ! = def_height ) {
2007-07-28 00:08:59 +02:00
/* Think about the overlapping toolbars when determining the minimum window size */
int free_height = _screen . height ;
const Window * wt = FindWindowById ( WC_STATUS_BAR , 0 ) ;
if ( wt ! = NULL ) free_height - = wt - > height ;
wt = FindWindowById ( WC_MAIN_TOOLBAR , 0 ) ;
if ( wt ! = NULL ) free_height - = wt - > height ;
2008-05-08 13:31:41 +02:00
int enlarge_x = max ( min ( def_width - this - > width , _screen . width - this - > width ) , 0 ) ;
int enlarge_y = max ( min ( def_height - this - > height , free_height - this - > height ) , 0 ) ;
2007-07-27 14:49:04 +02:00
/* X and Y has to go by step.. calculate it.
* The cast to int is necessary else x / y are implicitly casted to
* unsigned int , which won ' t work . */
2008-05-08 13:31:41 +02:00
if ( this - > resize . step_width > 1 ) enlarge_x - = enlarge_x % ( int ) this - > resize . step_width ;
if ( this - > resize . step_height > 1 ) enlarge_y - = enlarge_y % ( int ) this - > resize . step_height ;
2007-07-27 14:49:04 +02:00
2008-05-08 13:31:41 +02:00
ResizeWindow ( this , enlarge_x , enlarge_y ) ;
2007-07-27 21:09:31 +02:00
2008-05-10 15:46:36 +02:00
Point diff ;
diff . x = enlarge_x ;
diff . y = enlarge_y ;
2009-03-29 11:49:11 +02:00
this - > OnResize ( diff ) ;
2007-07-27 14:49:04 +02:00
}
2008-05-08 13:31:41 +02:00
int nx = this - > left ;
int ny = this - > top ;
2007-08-23 13:08:59 +02:00
2008-05-08 13:31:41 +02:00
if ( nx + this - > width > _screen . width ) nx - = ( nx + this - > width - _screen . width ) ;
2007-07-29 22:54:37 +02:00
2007-07-28 00:08:59 +02:00
const Window * wt = FindWindowById ( WC_MAIN_TOOLBAR , 0 ) ;
2008-05-11 13:41:18 +02:00
ny = max ( ny , ( wt = = NULL | | this = = wt | | this - > top = = 0 ) ? 0 : wt - > height ) ;
2007-08-23 13:08:59 +02:00
nx = max ( nx , 0 ) ;
2008-05-08 13:31:41 +02:00
if ( this - > viewport ! = NULL ) {
this - > viewport - > left + = nx - this - > left ;
this - > viewport - > top + = ny - this - > top ;
2007-08-23 13:08:59 +02:00
}
2008-05-08 13:31:41 +02:00
this - > left = nx ;
this - > top = ny ;
2007-07-28 00:08:59 +02:00
2008-05-08 13:31:41 +02:00
this - > SetDirty ( ) ;
2004-08-09 19:04:08 +02:00
}
2008-10-14 21:27:08 +02:00
/**
* Resize window towards the default size given in the window description .
* @ param desc the description to get the default size from .
*/
2008-05-11 13:41:18 +02:00
void Window : : FindWindowPlacementAndResize ( const WindowDesc * desc )
{
this - > FindWindowPlacementAndResize ( desc - > default_width , desc - > default_height ) ;
}
2006-09-02 22:09:16 +02:00
/**
* Open a new window . If there is no space for a new window , close an open
* window . Try to avoid stickied windows , but if there is no else , close one of
* those as well . Then make sure all created windows are below some always - on - top
* ones . Finally set all variables and call the WE_CREATE event
* @ param x offset in pixels from the left of the screen
* @ param y offset in pixels from the top of the screen
* @ param width width in pixels of the window
* @ param height height in pixels of the window
2007-04-09 17:06:24 +02:00
* @ param cls see WindowClass class of the window , used for identification and grouping
* @ param * widget see Widget pointer to the window layout and various elements
2008-04-07 22:28:58 +02:00
* @ return Window pointer of the newly created window
*/
2008-05-18 22:40:30 +02:00
Window : : Window ( int x , int y , int width , int height , WindowClass cls , const Widget * widget )
2006-09-02 22:09:16 +02:00
{
2009-06-04 16:34:38 +02:00
this - > Initialize ( x , y , width , height , cls , widget , NULL , 0 ) ;
2006-09-02 22:09:16 +02:00
}
2004-08-09 19:04:08 +02:00
2008-05-30 00:22:02 +02:00
/**
* Decide whether a given rectangle is a good place to open a completely visible new window .
* The new window should be within screen borders , and not overlap with another already
* existing window ( except for the main window in the background ) .
* @ param left Left edge of the rectangle
* @ param top Top edge of the rectangle
* @ param width Width of the rectangle
* @ param height Height of the rectangle
* @ param pos If rectangle is good , use this parameter to return the top - left corner of the new window
* @ return Boolean indication that the rectangle is a good place for the new window
*/
2007-04-26 19:32:54 +02:00
static bool IsGoodAutoPlace1 ( int left , int top , int width , int height , Point & pos )
2004-08-09 19:04:08 +02:00
{
2007-04-26 19:32:54 +02:00
int right = width + left ;
int bottom = height + top ;
2004-08-09 19:04:08 +02:00
2008-05-07 10:27:55 +02:00
if ( left < 0 | | top < 22 | | right > _screen . width | | bottom > _screen . height ) return false ;
2004-08-09 19:04:08 +02:00
2007-04-06 06:10:19 +02:00
/* Make sure it is not obscured by any window. */
2009-01-06 23:37:42 +01:00
const Window * w ;
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2005-11-14 20:48:04 +01:00
if ( w - > window_class = = WC_MAIN_WINDOW ) continue ;
2004-08-09 19:04:08 +02:00
2004-09-05 16:20:36 +02:00
if ( right > w - > left & &
2005-11-14 20:48:04 +01:00
w - > left + w - > width > left & &
2004-08-09 19:04:08 +02:00
bottom > w - > top & &
2005-11-14 20:48:04 +01:00
w - > top + w - > height > top ) {
return false ;
}
2004-09-05 16:20:36 +02:00
}
2004-08-09 19:04:08 +02:00
2007-04-26 19:32:54 +02:00
pos . x = left ;
pos . y = top ;
2004-08-09 19:04:08 +02:00
return true ;
}
2008-05-30 00:22:02 +02:00
/**
* Decide whether a given rectangle is a good place to open a mostly visible new window .
* The new window should be mostly within screen borders , and not overlap with another already
* existing window ( except for the main window in the background ) .
* @ param left Left edge of the rectangle
* @ param top Top edge of the rectangle
* @ param width Width of the rectangle
* @ param height Height of the rectangle
* @ param pos If rectangle is good , use this parameter to return the top - left corner of the new window
* @ return Boolean indication that the rectangle is a good place for the new window
*/
2007-04-26 19:32:54 +02:00
static bool IsGoodAutoPlace2 ( int left , int top , int width , int height , Point & pos )
2004-08-09 19:04:08 +02:00
{
2008-05-30 00:22:02 +02:00
/* Left part of the rectangle may be at most 1/4 off-screen,
* right part of the rectangle may be at most 1 / 2 off - screen
*/
2006-11-18 01:14:43 +01:00
if ( left < - ( width > > 2 ) | | left > _screen . width - ( width > > 1 ) ) return false ;
2008-05-30 00:22:02 +02:00
/* Bottom part of the rectangle may be at most 1/4 off-screen */
2006-11-18 01:14:43 +01:00
if ( top < 22 | | top > _screen . height - ( height > > 2 ) ) return false ;
2004-08-09 19:04:08 +02:00
2007-04-06 06:10:19 +02:00
/* Make sure it is not obscured by any window. */
2009-01-06 23:37:42 +01:00
const Window * w ;
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2005-11-14 20:48:04 +01:00
if ( w - > window_class = = WC_MAIN_WINDOW ) continue ;
2004-08-09 19:04:08 +02:00
2004-09-05 16:20:36 +02:00
if ( left + width > w - > left & &
2005-11-14 20:48:04 +01:00
w - > left + w - > width > left & &
2004-08-09 19:04:08 +02:00
top + height > w - > top & &
2005-11-14 20:48:04 +01:00
w - > top + w - > height > top ) {
return false ;
}
2004-09-05 16:20:36 +02:00
}
2004-08-09 19:04:08 +02:00
2007-04-26 19:32:54 +02:00
pos . x = left ;
pos . y = top ;
2004-08-09 19:04:08 +02:00
return true ;
}
2008-05-30 00:22:02 +02:00
/**
* Find a good place for opening a new window of a given width and height .
* @ param width Width of the new window
* @ param height Height of the new window
* @ return Top - left coordinate of the new window
*/
2005-01-22 23:47:58 +01:00
static Point GetAutoPlacePosition ( int width , int height )
{
2004-08-09 19:04:08 +02:00
Point pt ;
2008-05-30 00:22:02 +02:00
/* First attempt, try top-left of the screen */
2007-04-26 19:32:54 +02:00
if ( IsGoodAutoPlace1 ( 0 , 24 , width , height , pt ) ) return pt ;
2004-08-09 19:04:08 +02:00
2008-05-30 00:22:02 +02:00
/* Second attempt, try around all existing windows with a distance of 2 pixels.
* The new window must be entirely on - screen , and not overlap with an existing window .
* Eight starting points are tried , two at each corner .
*/
2009-01-06 23:37:42 +01:00
const Window * w ;
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2005-11-14 20:48:04 +01:00
if ( w - > window_class = = WC_MAIN_WINDOW ) continue ;
2004-08-09 19:04:08 +02:00
2007-04-26 19:32:54 +02:00
if ( IsGoodAutoPlace1 ( w - > left + w - > width + 2 , w - > top , width , height , pt ) ) return pt ;
if ( IsGoodAutoPlace1 ( w - > left - width - 2 , w - > top , width , height , pt ) ) return pt ;
if ( IsGoodAutoPlace1 ( w - > left , w - > top + w - > height + 2 , width , height , pt ) ) return pt ;
if ( IsGoodAutoPlace1 ( w - > left , w - > top - height - 2 , width , height , pt ) ) return pt ;
if ( IsGoodAutoPlace1 ( w - > left + w - > width + 2 , w - > top + w - > height - height , width , height , pt ) ) return pt ;
if ( IsGoodAutoPlace1 ( w - > left - width - 2 , w - > top + w - > height - height , width , height , pt ) ) return pt ;
if ( IsGoodAutoPlace1 ( w - > left + w - > width - width , w - > top + w - > height + 2 , width , height , pt ) ) return pt ;
if ( IsGoodAutoPlace1 ( w - > left + w - > width - width , w - > top - height - 2 , width , height , pt ) ) return pt ;
2004-09-05 16:20:36 +02:00
}
2008-05-30 00:22:02 +02:00
/* Third attempt, try around all existing windows with a distance of 2 pixels.
* The new window may be partly off - screen , and must not overlap with an existing window .
* Only four starting points are tried .
*/
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2005-11-14 20:48:04 +01:00
if ( w - > window_class = = WC_MAIN_WINDOW ) continue ;
2004-08-09 19:04:08 +02:00
2007-04-26 19:32:54 +02:00
if ( IsGoodAutoPlace2 ( w - > left + w - > width + 2 , w - > top , width , height , pt ) ) return pt ;
if ( IsGoodAutoPlace2 ( w - > left - width - 2 , w - > top , width , height , pt ) ) return pt ;
if ( IsGoodAutoPlace2 ( w - > left , w - > top + w - > height + 2 , width , height , pt ) ) return pt ;
if ( IsGoodAutoPlace2 ( w - > left , w - > top - height - 2 , width , height , pt ) ) return pt ;
2004-08-09 19:04:08 +02:00
}
2008-05-30 00:22:02 +02:00
/* Fourth and final attempt, put window at diagonal starting from (0, 24), try multiples
* of ( + 5 , + 5 )
*/
2009-01-06 23:37:42 +01:00
int left = 0 , top = 24 ;
2004-09-05 16:20:36 +02:00
2007-04-26 19:32:54 +02:00
restart :
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
if ( w - > left = = left & & w - > top = = top ) {
left + = 5 ;
top + = 5 ;
goto restart ;
2004-08-09 19:04:08 +02:00
}
}
2009-01-06 23:37:42 +01:00
pt . x = left ;
pt . y = top ;
return pt ;
2004-08-09 19:04:08 +02:00
}
2007-10-14 02:26:24 +02:00
/**
2008-05-04 10:49:57 +02:00
* Compute the position of the top - left corner of a new window that is opened .
2007-10-14 02:26:24 +02:00
*
2008-05-04 10:56:59 +02:00
* By default position a child window at an offset of 10 / 10 of its parent .
* With the exception of WC_BUILD_TOOLBAR ( build railway / roads / ship docks / airports )
* and WC_SCEN_LAND_GEN ( landscaping ) . Whose child window has an offset of 0 / 36 of
* its parent . So it ' s exactly under the parent toolbar and no buttons will be covered .
* However if it falls too extremely outside window positions , reposition
* it to an automatic place .
*
2007-10-14 02:26:24 +02:00
* @ param * desc The pointer to the WindowDesc to be created
* @ param window_number the window number of the new window
*
2008-05-04 10:49:57 +02:00
* @ return Coordinate of the top - left corner of the new window
2007-10-14 02:26:24 +02:00
*/
2008-05-04 10:49:57 +02:00
static Point LocalGetWindowPlacement ( const WindowDesc * desc , int window_number )
2004-08-09 19:04:08 +02:00
{
Point pt ;
Window * w ;
2006-11-11 10:47:44 +01:00
if ( desc - > parent_cls ! = 0 /* WC_MAIN_WINDOW */ & &
( w = FindWindowById ( desc - > parent_cls , window_number ) ) ! = NULL & &
w - > left < _screen . width - 20 & & w - > left > - 60 & & w - > top < _screen . height - 20 ) {
2007-10-14 02:26:24 +02:00
pt . x = w - > left + ( ( desc - > parent_cls = = WC_BUILD_TOOLBAR | | desc - > parent_cls = = WC_SCEN_LAND_GEN ) ? 0 : 10 ) ;
2007-07-27 14:49:04 +02:00
if ( pt . x > _screen . width + 10 - desc - > default_width ) {
pt . x = ( _screen . width + 10 - desc - > default_width ) - 20 ;
2006-11-11 10:47:44 +01:00
}
2007-10-14 02:26:24 +02:00
pt . y = w - > top + ( ( desc - > parent_cls = = WC_BUILD_TOOLBAR | | desc - > parent_cls = = WC_SCEN_LAND_GEN ) ? 36 : 10 ) ;
2004-08-09 19:04:08 +02:00
} else {
2006-11-11 11:12:00 +01:00
switch ( desc - > left ) {
2008-05-04 10:56:59 +02:00
case WDP_ALIGN_TBR : // Align the right side with the top toolbar
2006-11-11 11:12:00 +01:00
w = FindWindowById ( WC_MAIN_TOOLBAR , 0 ) ;
2007-07-27 14:49:04 +02:00
pt . x = ( w - > left + w - > width ) - desc - > default_width ;
2008-05-04 10:56:59 +02:00
break ;
case WDP_ALIGN_TBL : // Align the left side with the top toolbar
2006-11-11 11:12:00 +01:00
pt . x = FindWindowById ( WC_MAIN_TOOLBAR , 0 ) - > left ;
break ;
2008-05-04 10:56:59 +02:00
case WDP_AUTO : // Find a good automatic position for the window
2008-05-04 10:49:57 +02:00
return GetAutoPlacePosition ( desc - > default_width , desc - > default_height ) ;
2008-05-04 10:56:59 +02:00
case WDP_CENTER : // Centre the window horizontally
2007-07-27 14:49:04 +02:00
pt . x = ( _screen . width - desc - > default_width ) / 2 ;
2006-11-11 11:12:00 +01:00
break ;
2008-05-04 10:56:59 +02:00
2006-11-11 11:12:00 +01:00
default :
pt . x = desc - > left ;
if ( pt . x < 0 ) pt . x + = _screen . width ; // negative is from right of the screen
}
switch ( desc - > top ) {
2008-05-04 10:56:59 +02:00
case WDP_CENTER : // Centre the window vertically
2007-07-27 14:49:04 +02:00
pt . y = ( _screen . height - desc - > default_height ) / 2 ;
2006-11-11 11:12:00 +01:00
break ;
2008-05-04 10:56:59 +02:00
2006-11-11 11:12:00 +01:00
/* WDP_AUTO sets the position at once and is controlled by desc->left.
* Both left and top must be set to WDP_AUTO */
case WDP_AUTO :
NOT_REACHED ( ) ;
assert ( desc - > left = = WDP_AUTO & & desc - > top ! = WDP_AUTO ) ;
/* fallthrough */
2008-05-04 10:56:59 +02:00
2006-11-11 11:12:00 +01:00
default :
pt . y = desc - > top ;
if ( pt . y < 0 ) pt . y + = _screen . height ; // negative is from bottom of the screen
break ;
2004-08-09 19:04:08 +02:00
}
}
2008-05-04 10:49:57 +02:00
return pt ;
}
/**
* Set the positions of a new window from a WindowDesc and open it .
*
* @ param * desc The pointer to the WindowDesc to be created
* @ param window_number the window number of the new window
*
* @ return Window pointer of the newly created window
*/
2008-05-13 16:43:33 +02:00
Window : : Window ( const WindowDesc * desc , WindowNumber window_number )
2008-05-04 10:49:57 +02:00
{
Point pt = LocalGetWindowPlacement ( desc , window_number ) ;
2009-06-04 16:34:38 +02:00
this - > Initialize ( pt . x , pt . y , desc - > minimum_width , desc - > minimum_height , desc - > cls , desc - > GetWidgets ( ) , NULL , window_number ) ;
this - > desc_flags = desc - > flags ;
}
/**
* Perform initialization of the # Window with nested widgets , to allow use .
* @ param desc Window description .
* @ param window_number Number of the new window .
*/
void Window : : InitNested ( const WindowDesc * desc , WindowNumber window_number )
{
NWidgetBase * nested_root = MakeNWidgets ( desc - > nwid_parts , desc - > nwid_length ) ;
Point pt = LocalGetWindowPlacement ( desc , window_number ) ;
this - > Initialize ( pt . x , pt . y , desc - > minimum_width , desc - > minimum_height , desc - > cls , NULL , nested_root , window_number ) ; // min_width and min_height are not used.
2008-05-08 13:31:41 +02:00
this - > desc_flags = desc - > flags ;
2009-06-04 16:34:38 +02:00
this - > FindWindowPlacementAndResize ( desc - > default_width , desc - > default_height ) ;
}
/** Empty constructor, initialization has been moved to #InitNested() called from the constructor of the derived class. */
Window : : Window ( )
{
2006-09-02 22:09:16 +02:00
}
2006-11-18 01:14:43 +01:00
/** 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
2007-04-09 17:06:24 +02:00
* @ param x position x to query
* @ param y position y to query
2006-11-18 01:14:43 +01:00
* @ return a pointer to the found window if any , NULL otherwise */
2004-08-09 19:04:08 +02:00
Window * FindWindowFromPt ( int x , int y )
{
2009-01-06 23:37:42 +01:00
Window * w ;
FOR_ALL_WINDOWS_FROM_FRONT ( w ) {
2007-11-24 11:38:43 +01:00
if ( IsInsideBS ( x , w - > left , w - > width ) & & IsInsideBS ( y , w - > top , w - > height ) ) {
2005-11-14 20:48:04 +01:00
return w ;
}
2004-08-09 19:04:08 +02:00
}
return NULL ;
}
2008-04-13 21:01:26 +02:00
/**
* ( re ) initialize the windowing system
*/
2007-03-07 12:47:46 +01:00
void InitWindowSystem ( )
2004-09-03 21:59:05 +02:00
{
2004-08-25 10:55:53 +02:00
IConsoleClose ( ) ;
2005-03-09 20:48:20 +01:00
2009-01-07 17:11:27 +01:00
_z_back_window = NULL ;
_z_front_window = NULL ;
2009-02-09 02:22:29 +01:00
_focused_window = NULL ;
2008-04-19 15:28:48 +02:00
_mouseover_last_w = NULL ;
2008-05-29 12:16:59 +02:00
_scrolling_viewport = 0 ;
2004-08-09 19:04:08 +02:00
}
2008-04-13 21:01:26 +02:00
/**
* Close down the windowing system
*/
2007-03-07 12:47:46 +01:00
void UnInitWindowSystem ( )
2005-03-09 20:48:20 +01:00
{
2009-01-07 19:59:46 +01:00
Window * w ;
FOR_ALL_WINDOWS_FROM_FRONT ( w ) delete w ;
for ( w = _z_front_window ; w ! = NULL ; /* nothing */ ) {
Window * to_del = w ;
w = w - > z_back ;
free ( to_del ) ;
}
_z_front_window = NULL ;
_z_back_window = NULL ;
2005-03-09 20:48:20 +01:00
}
2008-04-13 21:01:26 +02:00
/**
* Reset the windowing system , by means of shutting it down followed by re - initialization
*/
2007-03-07 12:47:46 +01:00
void ResetWindowSystem ( )
2005-03-09 20:48:20 +01:00
{
UnInitWindowSystem ( ) ;
InitWindowSystem ( ) ;
2005-05-02 19:14:31 +02:00
_thd . pos . x = 0 ;
_thd . pos . y = 0 ;
2006-01-24 19:08:04 +01:00
_thd . new_pos . x = 0 ;
_thd . new_pos . y = 0 ;
2005-03-09 20:48:20 +01:00
}
2007-03-07 12:47:46 +01:00
static void DecreaseWindowCounters ( )
2004-08-09 19:04:08 +02:00
{
2009-01-06 23:37:42 +01:00
Window * w ;
FOR_ALL_WINDOWS_FROM_FRONT ( w ) {
2007-04-06 06:10:19 +02:00
/* Unclick scrollbar buttons if they are pressed. */
2004-08-09 19:04:08 +02:00
if ( w - > flags4 & ( WF_SCROLL_DOWN | WF_SCROLL_UP ) ) {
w - > flags4 & = ~ ( WF_SCROLL_DOWN | WF_SCROLL_UP ) ;
2008-05-07 00:08:18 +02:00
w - > SetDirty ( ) ;
2004-08-09 19:04:08 +02:00
}
2008-05-10 15:46:36 +02:00
w - > OnMouseLoop ( ) ;
2004-08-09 19:04:08 +02:00
}
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_FRONT ( w ) {
2009-06-01 13:43:36 +02:00
if ( ( w - > flags4 & WF_TIMEOUT_MASK ) & & ! ( - - w - > flags4 & WF_TIMEOUT_MASK ) ) {
2008-05-10 15:46:36 +02:00
w - > OnTimeout ( ) ;
2007-12-08 02:20:47 +01:00
if ( w - > desc_flags & WDF_UNCLICK_BUTTONS ) w - > RaiseButtons ( ) ;
2004-08-09 19:04:08 +02:00
}
}
}
2007-03-07 12:47:46 +01:00
Window * GetCallbackWnd ( )
2004-08-09 19:04:08 +02:00
{
return FindWindowById ( _thd . window_class , _thd . window_number ) ;
}
2007-03-07 12:47:46 +01:00
static void HandlePlacePresize ( )
2004-08-09 19:04:08 +02:00
{
2005-11-14 20:48:04 +01:00
if ( _special_mouse_mode ! = WSM_PRESIZE ) return ;
2004-08-09 19:04:08 +02:00
2008-05-07 10:27:55 +02:00
Window * w = GetCallbackWnd ( ) ;
2005-11-14 20:48:04 +01:00
if ( w = = NULL ) return ;
2004-08-09 19:04:08 +02:00
2008-05-10 15:46:36 +02:00
Point pt = GetTileBelowCursor ( ) ;
if ( pt . x = = - 1 ) {
2004-08-09 19:04:08 +02:00
_thd . selend . x = - 1 ;
return ;
}
2008-05-10 15:46:36 +02:00
w - > OnPlacePresize ( pt , TileVirtXY ( pt . x , pt . y ) ) ;
2004-08-09 19:04:08 +02:00
}
2007-03-07 12:47:46 +01:00
static bool HandleDragDrop ( )
2004-08-09 19:04:08 +02:00
{
2005-11-14 20:48:04 +01:00
if ( _special_mouse_mode ! = WSM_DRAGDROP ) return true ;
if ( _left_button_down ) return false ;
2004-09-05 16:20:36 +02:00
2008-05-07 10:27:55 +02:00
Window * w = GetCallbackWnd ( ) ;
2004-08-09 19:04:08 +02:00
2005-11-14 20:48:04 +01:00
if ( w ! = NULL ) {
2007-04-06 06:10:19 +02:00
/* send an event in client coordinates. */
2008-05-10 15:46:36 +02:00
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 ) ) ;
2004-08-09 19:04:08 +02:00
}
2008-02-17 13:21:05 +01:00
ResetObjectToPlace ( ) ;
2004-08-09 19:04:08 +02:00
return false ;
}
2007-03-07 12:47:46 +01:00
static bool HandleMouseOver ( )
2004-12-04 18:54:56 +01:00
{
2008-04-13 21:06:30 +02:00
Window * w = FindWindowFromPt ( _cursor . pos . x , _cursor . pos . y ) ;
2004-12-04 18:54:56 +01:00
2007-04-06 06:10:19 +02:00
/* We changed window, put a MOUSEOVER event to the last window */
2008-04-13 21:06:30 +02:00
if ( _mouseover_last_w ! = NULL & & _mouseover_last_w ! = w ) {
/* Reset mouse-over coordinates of previous window */
2008-05-10 15:46:36 +02:00
Point pt = { - 1 , - 1 } ;
_mouseover_last_w - > OnMouseOver ( pt , 0 ) ;
2004-12-04 18:54:56 +01:00
}
2008-04-13 21:06:30 +02:00
/* _mouseover_last_w will get reset when the window is deleted, see DeleteWindow() */
_mouseover_last_w = w ;
2004-12-04 18:54:56 +01:00
2005-11-14 20:48:04 +01:00
if ( w ! = NULL ) {
2007-04-06 06:10:19 +02:00
/* send an event in client coordinates. */
2008-05-10 15:46:36 +02:00
Point pt = { _cursor . pos . x - w - > left , _cursor . pos . y - w - > top } ;
int widget = 0 ;
2004-12-04 18:54:56 +01:00
if ( w - > widget ! = NULL ) {
2008-05-10 15:46:36 +02:00
widget = GetWidgetFromPos ( w , pt . x , pt . y ) ;
2004-12-04 18:54:56 +01:00
}
2008-05-10 15:46:36 +02:00
w - > OnMouseOver ( pt , widget ) ;
2004-12-04 18:54:56 +01:00
}
2007-04-06 06:10:19 +02:00
/* Mouseover never stops execution */
2004-12-04 18:54:56 +01:00
return true ;
}
2008-04-07 22:28:58 +02:00
/**
* Resize the window .
* Update all the widgets of a window based on their resize flags
2006-12-07 01:47:35 +01:00
* Both the areas of the old window and the new sized window are set dirty
* ensuring proper redrawal .
2009-06-01 15:28:05 +02:00
* @ 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
2008-04-07 22:28:58 +02:00
*/
2009-06-01 15:28:05 +02:00
void ResizeWindow ( Window * w , int delta_x , int delta_y )
2006-12-07 01:47:35 +01:00
{
2009-06-01 15:28:05 +02:00
if ( delta_x = = 0 & & delta_y = = 0 ) return ;
2006-12-07 01:47:35 +01:00
2008-05-07 00:08:18 +02:00
w - > SetDirty ( ) ;
2006-12-07 01:47:35 +01:00
2009-06-04 16:07:05 +02:00
if ( w - > nested_root ! = NULL ) {
uint new_xinc = max ( 0u , ( w - > nested_root - > resize_x = = 0 ) ? 0 : ( w - > nested_root - > current_x - w - > nested_root - > smallest_x ) + delta_x ) ;
uint new_yinc = max ( 0u , ( w - > nested_root - > resize_y = = 0 ) ? 0 : ( 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 ) ;
2006-12-07 01:47:35 +01:00
2009-06-04 16:07:05 +02:00
w - > nested_root - > AssignSizePosition ( ST_RESIZE , 0 , 0 , w - > nested_root - > smallest_x + new_xinc , w - > nested_root - > smallest_y + new_yinc , false , false , false ) ;
w - > width = w - > nested_root - > current_x ;
w - > height = w - > nested_root - > current_y ;
} else {
assert ( w - > widget ! = NULL ) ;
2006-12-07 01:47:35 +01:00
2009-06-04 16:07:05 +02:00
bool resize_height = false ;
bool resize_width = false ;
for ( Widget * wi = w - > widget ; wi - > type ! = WWT_LAST ; wi + + ) {
/* Isolate the resizing flags */
byte rsizeflag = GB ( wi - > display_flags , 0 , 4 ) ;
2006-12-07 01:47:35 +01:00
2009-06-04 16:07:05 +02:00
if ( rsizeflag = = RESIZE_NONE ) continue ;
2006-12-07 01:47:35 +01:00
2009-06-04 16:07:05 +02:00
/* Resize the widget based on its resize-flag */
if ( rsizeflag & RESIZE_LEFT ) {
wi - > left + = delta_x ;
resize_width = true ;
}
2006-12-07 01:47:35 +01:00
2009-06-04 16:07:05 +02:00
if ( rsizeflag & RESIZE_RIGHT ) {
wi - > right + = delta_x ;
resize_width = true ;
}
if ( rsizeflag & RESIZE_TOP ) {
wi - > top + = delta_y ;
resize_height = true ;
}
2006-12-07 01:47:35 +01:00
2009-06-04 16:07:05 +02:00
if ( rsizeflag & RESIZE_BOTTOM ) {
wi - > bottom + = delta_y ;
resize_height = true ;
}
}
/* We resized at least 1 widget, so let's resize the window totally */
if ( resize_width ) w - > width + = delta_x ;
if ( resize_height ) w - > height + = delta_y ;
}
2008-05-07 00:08:18 +02:00
w - > SetDirty ( ) ;
2006-12-07 01:47:35 +01:00
}
2005-11-04 15:01:44 +01:00
2009-06-05 09:25:26 +02:00
/** The minimum number of pixels of the title bar must be visible in both the X or Y direction */
static const int MIN_VISIBLE_TITLE_BAR = 13 ;
/** Direction for moving the window. */
enum PreventHideDirection {
PHD_UP , ///< Above v is a safe position.
PHD_DOWN , ///< Below v is a safe position.
} ;
/**
* Do not allow hiding of the rectangle with base coordinates \ a nx and \ a ny behind window \ a v .
* If needed , move the window base coordinates to keep it visible .
* @ param nx Base horizontal coordinate of the rectangle .
* @ param ny Base vertical coordinate of the rectangle .
* @ param rect Rectangle that must stay visible for # MIN_VISIBLE_TITLE_BAR pixels ( horizontally , vertically , or both )
* @ param v Window lying in front of the rectangle .
* @ param px Previous horizontal base coordinate .
* @ param dir If no room horizontally , move the rectangle to the indicated position .
*/
void PreventHiding ( int * nx , int * ny , const Rect & rect , const Window * v , int px , PreventHideDirection dir )
{
if ( v = = NULL ) return ;
int v_bottom = v - > top + v - > height ;
int v_right = v - > left + v - > width ;
int safe_y = ( dir = = PHD_UP ) ? ( v - > top - MIN_VISIBLE_TITLE_BAR - rect . top ) : ( v_bottom + MIN_VISIBLE_TITLE_BAR - rect . bottom ) ; // Compute safe vertical position.
if ( * ny + rect . top < = v - > top - MIN_VISIBLE_TITLE_BAR ) return ; // Above v is enough space
if ( * ny + rect . bottom > = v_bottom + MIN_VISIBLE_TITLE_BAR ) return ; // Below v is enough space
/* Vertically, the rectangle is hidden behind v. */
if ( * nx + rect . left + MIN_VISIBLE_TITLE_BAR < v - > left ) { // At left of v.
if ( v - > left < MIN_VISIBLE_TITLE_BAR ) * ny = safe_y ; // But enough room, force it to a safe position.
return ;
}
if ( * nx + rect . right - MIN_VISIBLE_TITLE_BAR > v_right ) { // At right of v.
if ( v_right > _screen . width - MIN_VISIBLE_TITLE_BAR ) * ny = safe_y ; // Not enough room, force it to a safe position.
return ;
}
/* Horizontally also hidden, force movement to a safe area. */
if ( px + rect . left < v - > left & & v - > left > = MIN_VISIBLE_TITLE_BAR ) { // Coming from the left, and enough room there.
* nx = v - > left - MIN_VISIBLE_TITLE_BAR - rect . left ;
} else if ( px + rect . right > v_right & & v_right < = _screen . width - MIN_VISIBLE_TITLE_BAR ) { // Coming from the right, and enough room there.
* nx = v_right + MIN_VISIBLE_TITLE_BAR - rect . right ;
} else {
* ny = safe_y ;
}
}
2009-03-06 04:01:35 +01:00
static bool _dragging_window ; ///< A window is being dragged or resized.
2005-11-04 15:01:44 +01:00
2007-03-07 12:47:46 +01:00
static bool HandleWindowDragging ( )
2004-08-09 19:04:08 +02:00
{
2007-04-06 06:10:19 +02:00
/* Get out immediately if no window is being dragged at all. */
2005-11-14 20:48:04 +01:00
if ( ! _dragging_window ) return true ;
2004-08-09 19:04:08 +02:00
2007-04-06 06:10:19 +02:00
/* Otherwise find the window... */
2009-01-06 23:37:42 +01:00
Window * w ;
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2004-11-10 22:14:16 +01:00
if ( w - > flags4 & WF_DRAGGING ) {
2007-04-06 06:10:19 +02:00
/* Stop the dragging if the left mouse button was released */
2004-08-09 19:04:08 +02:00
if ( ! _left_button_down ) {
2004-11-10 22:14:16 +01:00
w - > flags4 & = ~ WF_DRAGGING ;
2004-08-09 19:04:08 +02:00
break ;
}
2008-05-07 00:08:18 +02:00
w - > SetDirty ( ) ;
2004-08-09 19:04:08 +02:00
2008-05-07 10:27:55 +02:00
int x = _cursor . pos . x + _drag_delta . x ;
int y = _cursor . pos . y + _drag_delta . y ;
int nx = x ;
int ny = y ;
2004-11-10 22:14:16 +01:00
2008-05-29 17:13:28 +02:00
if ( _settings_client . gui . window_snap_radius ! = 0 ) {
2009-01-06 23:37:42 +01:00
const Window * v ;
2006-11-18 17:47:02 +01:00
2008-05-29 17:13:28 +02:00
int hsnap = _settings_client . gui . window_snap_radius ;
int vsnap = _settings_client . gui . window_snap_radius ;
2004-11-11 22:20:15 +01:00
int delta ;
2004-11-10 22:14:16 +01:00
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_BACK ( v ) {
2004-11-10 22:14:16 +01:00
if ( v = = w ) continue ; // Don't snap at yourself
if ( y + w - > height > v - > top & & y < v - > top + v - > height ) {
2007-04-06 06:10:19 +02:00
/* Your left border <-> other right border */
2004-11-10 22:14:16 +01:00
delta = abs ( v - > left + v - > width - x ) ;
if ( delta < = hsnap ) {
nx = v - > left + v - > width ;
hsnap = delta ;
}
2007-04-06 06:10:19 +02:00
/* Your right border <-> other left border */
2004-11-10 22:14:16 +01:00
delta = abs ( v - > left - x - w - > width ) ;
if ( delta < = hsnap ) {
nx = v - > left - w - > width ;
hsnap = delta ;
}
}
2004-11-11 22:20:15 +01:00
if ( w - > top + w - > height > = v - > top & & w - > top < = v - > top + v - > height ) {
2007-04-06 06:10:19 +02:00
/* Your left border <-> other left border */
2004-11-11 22:20:15 +01:00
delta = abs ( v - > left - x ) ;
if ( delta < = hsnap ) {
nx = v - > left ;
hsnap = delta ;
}
2007-04-06 06:10:19 +02:00
/* Your right border <-> other right border */
2004-11-11 22:20:15 +01:00
delta = abs ( v - > left + v - > width - x - w - > width ) ;
if ( delta < = hsnap ) {
nx = v - > left + v - > width - w - > width ;
hsnap = delta ;
}
}
2004-11-10 22:14:16 +01:00
if ( x + w - > width > v - > left & & x < v - > left + v - > width ) {
2007-04-06 06:10:19 +02:00
/* Your top border <-> other bottom border */
2004-11-10 22:14:16 +01:00
delta = abs ( v - > top + v - > height - y ) ;
if ( delta < = vsnap ) {
ny = v - > top + v - > height ;
vsnap = delta ;
}
2007-04-06 06:10:19 +02:00
/* Your bottom border <-> other top border */
2004-11-10 22:14:16 +01:00
delta = abs ( v - > top - y - w - > height ) ;
if ( delta < = vsnap ) {
ny = v - > top - w - > height ;
vsnap = delta ;
}
}
2004-11-11 22:20:15 +01:00
if ( w - > left + w - > width > = v - > left & & w - > left < = v - > left + v - > width ) {
2007-04-06 06:10:19 +02:00
/* Your top border <-> other top border */
2004-11-11 22:20:15 +01:00
delta = abs ( v - > top - y ) ;
if ( delta < = vsnap ) {
ny = v - > top ;
vsnap = delta ;
}
2007-04-06 06:10:19 +02:00
/* Your bottom border <-> other bottom border */
2004-11-11 22:20:15 +01:00
delta = abs ( v - > top + v - > height - y - w - > height ) ;
if ( delta < = vsnap ) {
ny = v - > top + v - > height - w - > height ;
vsnap = delta ;
}
}
2004-08-09 19:04:08 +02:00
}
}
2004-09-05 16:20:36 +02:00
2009-06-04 16:07:05 +02:00
/* Search for the title bar rectangle. */
Rect caption_rect ;
if ( w - > widget ! = NULL ) {
const Widget * caption = w - > GetWidgetOfType ( WWT_CAPTION ) ;
assert ( caption ! = NULL ) ;
caption_rect . left = caption - > left ;
caption_rect . right = caption - > right ;
caption_rect . top = caption - > top ;
caption_rect . bottom = caption - > bottom ;
} else {
assert ( w - > nested_root ! = NULL ) ;
const NWidgetBase * caption = w - > nested_root - > GetWidgetOfType ( WWT_CAPTION ) ;
assert ( caption ! = NULL ) ;
caption_rect . left = caption - > pos_x ;
caption_rect . right = caption - > pos_x + caption - > current_x ;
caption_rect . top = caption - > pos_y ;
caption_rect . bottom = caption - > pos_y + caption - > current_y ;
}
2009-03-18 00:26:28 +01:00
/* Make sure the window doesn't leave the screen */
2009-06-04 16:07:05 +02:00
nx = Clamp ( nx , MIN_VISIBLE_TITLE_BAR - caption_rect . right , _screen . width - MIN_VISIBLE_TITLE_BAR - caption_rect . left ) ;
2009-03-18 00:26:28 +01:00
ny = Clamp ( ny , 0 , _screen . height - MIN_VISIBLE_TITLE_BAR ) ;
2004-11-10 22:14:16 +01:00
2009-06-05 09:25:26 +02:00
/* Make sure the title bar isn't hidden behind the main tool bar or the status bar. */
PreventHiding ( & nx , & ny , caption_rect , FindWindowById ( WC_MAIN_TOOLBAR , 0 ) , w - > left , PHD_DOWN ) ;
PreventHiding ( & nx , & ny , caption_rect , FindWindowById ( WC_STATUS_BAR , 0 ) , w - > left , PHD_UP ) ;
2004-11-13 11:53:42 +01:00
2004-11-10 22:14:16 +01:00
if ( w - > viewport ! = NULL ) {
w - > viewport - > left + = nx - w - > left ;
w - > viewport - > top + = ny - w - > top ;
}
w - > left = nx ;
w - > top = ny ;
2008-05-07 00:08:18 +02:00
w - > SetDirty ( ) ;
2005-01-03 20:45:18 +01:00
return false ;
} else if ( w - > flags4 & WF_SIZING ) {
/* Stop the sizing if the left mouse button was released */
if ( ! _left_button_down ) {
w - > flags4 & = ~ WF_SIZING ;
2008-05-07 00:08:18 +02:00
w - > SetDirty ( ) ;
2005-01-03 20:45:18 +01:00
break ;
}
2009-03-18 02:06:48 +01:00
/* Compute difference in pixels between cursor position and reference point in the window.
* If resizing the left edge of the window , moving to the left makes the window bigger not smaller .
*/
int x , y = _cursor . pos . y - _drag_delta . y ;
if ( w - > flags4 & WF_SIZING_LEFT ) {
x = _drag_delta . x - _cursor . pos . x ;
} else {
x = _cursor . pos . x - _drag_delta . x ;
}
2005-01-03 20:45:18 +01:00
2009-06-04 16:07:05 +02:00
if ( w - > nested_root ! = NULL ) {
/* Nested widgets also allow resize.step_width and/or resize.step_height to become 0 which means no resize is possible. */
if ( w - > resize . step_width = = 0 ) x = 0 ;
if ( w - > resize . step_height = = 0 ) y = 0 ;
}
2005-11-18 21:28:55 +01:00
/* X and Y has to go by step.. calculate it.
* The cast to int is necessary else x / y are implicitly casted to
* unsigned int , which won ' t work . */
2009-06-04 16:07:05 +02:00
if ( w - > resize . step_width > 1 ) x - = x % ( int ) w - > resize . step_width ;
2005-11-18 21:28:55 +01:00
if ( w - > resize . step_height > 1 ) y - = y % ( int ) w - > resize . step_height ;
2005-01-03 20:45:18 +01:00
/* Check if we don't go below the minimum set size */
2009-03-18 02:06:48 +01:00
if ( ( int ) w - > width + x < ( int ) w - > resize . width ) {
2005-01-03 20:45:18 +01:00
x = w - > resize . width - w - > width ;
2009-03-18 02:06:48 +01:00
}
if ( ( int ) w - > height + y < ( int ) w - > resize . height ) {
2005-01-03 20:45:18 +01:00
y = w - > resize . height - w - > height ;
2009-03-18 02:06:48 +01:00
}
2005-01-03 20:45:18 +01:00
/* Window already on size */
2005-11-14 20:48:04 +01:00
if ( x = = 0 & & y = = 0 ) return false ;
2005-01-03 20:45:18 +01:00
2009-03-18 02:06:48 +01:00
/* Now find the new cursor pos.. this is NOT _cursor, because we move in steps. */
2005-01-03 20:45:18 +01:00
_drag_delta . y + = y ;
2009-06-01 13:43:36 +02:00
if ( ( w - > flags4 & WF_SIZING_LEFT ) & & x ! = 0 ) {
2009-03-18 02:06:48 +01:00
_drag_delta . x - = x ; // x > 0 -> window gets longer -> left-edge moves to left -> subtract x to get new position.
w - > SetDirty ( ) ;
w - > left - = x ; // If dragging left edge, move left window edge in opposite direction by the same amount.
/* ResizeWindow() below ensures marking new position as dirty. */
} else {
_drag_delta . x + = x ;
}
2005-01-03 20:45:18 +01:00
2006-12-07 01:47:35 +01:00
/* ResizeWindow sets both pre- and after-size to dirty for redrawal */
ResizeWindow ( w , x , y ) ;
2005-01-03 20:45:18 +01:00
2008-05-10 15:46:36 +02:00
Point diff ;
diff . x = x ;
diff . y = y ;
2009-03-29 11:49:11 +02:00
w - > OnResize ( diff ) ;
2004-08-09 19:04:08 +02:00
return false ;
}
}
_dragging_window = false ;
return false ;
}
2008-04-07 22:28:58 +02:00
/**
* Start window dragging
* @ param w Window to start dragging
*/
2006-11-18 17:47:02 +01:00
static void StartWindowDrag ( Window * w )
2004-08-09 19:04:08 +02:00
{
w - > flags4 | = WF_DRAGGING ;
_dragging_window = true ;
2005-01-03 20:45:18 +01:00
2004-11-10 22:14:16 +01:00
_drag_delta . x = w - > left - _cursor . pos . x ;
_drag_delta . y = w - > top - _cursor . pos . y ;
2005-01-03 20:45:18 +01:00
2006-11-18 17:47:02 +01:00
BringWindowToFront ( w ) ;
2004-08-09 19:04:08 +02:00
DeleteWindowById ( WC_DROPDOWN_MENU , 0 ) ;
}
2008-04-07 22:28:58 +02:00
/**
2009-03-18 02:06:48 +01:00
* Start resizing a window .
* @ param w Window to start resizing .
* @ param to_left Whether to drag towards the left or not
2008-04-07 22:28:58 +02:00
*/
2009-03-18 02:06:48 +01:00
static void StartWindowSizing ( Window * w , bool to_left )
2004-08-09 19:04:08 +02:00
{
2009-03-18 02:06:48 +01:00
w - > flags4 | = to_left ? WF_SIZING_LEFT : WF_SIZING_RIGHT ;
2004-08-09 19:04:08 +02:00
_dragging_window = true ;
2005-01-03 20:45:18 +01:00
_drag_delta . x = _cursor . pos . x ;
_drag_delta . y = _cursor . pos . y ;
2006-11-18 17:47:02 +01:00
BringWindowToFront ( w ) ;
2004-08-09 19:04:08 +02:00
DeleteWindowById ( WC_DROPDOWN_MENU , 0 ) ;
}
2007-03-07 12:47:46 +01:00
static bool HandleScrollbarScrolling ( )
2004-08-09 19:04:08 +02:00
{
2009-01-06 23:37:42 +01:00
Window * w ;
2004-08-09 19:04:08 +02:00
2007-04-06 06:10:19 +02:00
/* Get out quickly if no item is being scrolled */
2005-11-14 20:48:04 +01:00
if ( ! _scrolling_scrollbar ) return true ;
2004-08-09 19:04:08 +02:00
2007-04-06 06:10:19 +02:00
/* Find the scrolling window */
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2004-08-09 19:04:08 +02:00
if ( w - > flags4 & WF_SCROLL_MIDDLE ) {
2007-04-06 06:10:19 +02:00
/* Abort if no button is clicked any more. */
2004-08-09 19:04:08 +02:00
if ( ! _left_button_down ) {
w - > flags4 & = ~ WF_SCROLL_MIDDLE ;
2008-05-07 00:08:18 +02:00
w - > SetDirty ( ) ;
2004-08-09 19:04:08 +02:00
break ;
2004-09-05 16:20:36 +02:00
}
2004-08-09 19:04:08 +02:00
2008-05-07 10:27:55 +02:00
int i ;
Scrollbar * sb ;
2004-08-09 19:04:08 +02:00
if ( w - > flags4 & WF_HSCROLL ) {
sb = & w - > hscroll ;
i = _cursor . pos . x - _cursorpos_drag_start . x ;
2005-01-02 18:23:04 +01:00
} else if ( w - > flags4 & WF_SCROLL2 ) {
sb = & w - > vscroll2 ;
i = _cursor . pos . y - _cursorpos_drag_start . y ;
2004-08-09 19:04:08 +02:00
} else {
sb = & w - > vscroll ;
i = _cursor . pos . y - _cursorpos_drag_start . y ;
}
2007-04-06 06:10:19 +02:00
/* Find the item we want to move to and make sure it's inside bounds. */
2008-05-07 10:27:55 +02:00
int pos = min ( max ( 0 , i + _scrollbar_start_pos ) * sb - > count / _scrollbar_size , max ( 0 , sb - > count - sb - > cap ) ) ;
2004-08-09 19:04:08 +02:00
if ( pos ! = sb - > pos ) {
sb - > pos = pos ;
2008-05-07 00:08:18 +02:00
w - > SetDirty ( ) ;
2004-08-09 19:04:08 +02:00
}
return false ;
2004-09-05 16:20:36 +02:00
}
2004-08-09 19:04:08 +02:00
}
2004-09-05 16:20:36 +02:00
2004-08-09 19:04:08 +02:00
_scrolling_scrollbar = false ;
return false ;
}
2007-03-07 12:47:46 +01:00
static bool HandleViewportScroll ( )
2004-08-09 19:04:08 +02:00
{
2008-05-29 17:13:28 +02:00
bool scrollwheel_scrolling = _settings_client . gui . scrollwheel_scrolling = = 1 & & ( _cursor . v_wheel ! = 0 | | _cursor . h_wheel ! = 0 ) ;
2007-03-11 11:55:35 +01:00
2005-11-14 20:48:04 +01:00
if ( ! _scrolling_viewport ) return true ;
2004-08-09 19:04:08 +02:00
2008-05-07 10:27:55 +02:00
Window * w = FindWindowFromPt ( _cursor . pos . x , _cursor . pos . y ) ;
2006-08-21 16:34:59 +02:00
2009-01-02 23:42:05 +01:00
if ( ! ( _right_button_down | | scrollwheel_scrolling | | ( _settings_client . gui . left_mouse_btn_scrolling & & _left_button_down ) ) | | w = = NULL ) {
2007-11-11 13:26:44 +01:00
_cursor . fix_at = false ;
_scrolling_viewport = false ;
return true ;
}
2008-05-11 17:08:44 +02:00
if ( w = = FindWindowById ( WC_MAIN_WINDOW , 0 ) & & w - > viewport - > follow_vehicle ! = INVALID_VEHICLE ) {
2007-10-20 02:09:39 +02:00
/* If the main window is following a vehicle, then first let go of it! */
2009-05-17 01:34:14 +02:00
const Vehicle * veh = Vehicle : : Get ( w - > viewport - > follow_vehicle ) ;
2009-03-15 16:25:18 +01:00
ScrollMainWindowTo ( veh - > x_pos , veh - > y_pos , veh - > z_pos , true ) ; // This also resets follow_vehicle
2007-10-20 02:09:39 +02:00
return true ;
}
2008-05-10 15:46:36 +02:00
Point delta ;
2009-01-02 23:42:05 +01:00
if ( _settings_client . gui . reverse_scroll | | ( _settings_client . gui . left_mouse_btn_scrolling & & _left_button_down ) ) {
2008-05-10 15:46:36 +02:00
delta . x = - _cursor . delta . x ;
delta . y = - _cursor . delta . y ;
2005-11-19 13:37:28 +01:00
} else {
2008-05-10 15:46:36 +02:00
delta . x = _cursor . delta . x ;
delta . y = _cursor . delta . y ;
2005-11-19 13:37:28 +01:00
}
2007-03-11 11:55:35 +01:00
if ( scrollwheel_scrolling ) {
/* We are using scrollwheels for scrolling */
2008-05-10 15:46:36 +02:00
delta . x = _cursor . h_wheel ;
delta . y = _cursor . v_wheel ;
2007-03-11 11:55:35 +01:00
_cursor . v_wheel = 0 ;
_cursor . h_wheel = 0 ;
}
2006-08-21 16:34:59 +02:00
/* Create a scroll-event and send it to the window */
2008-05-10 15:46:36 +02:00
w - > OnScroll ( delta ) ;
2006-02-06 10:18:04 +01:00
_cursor . delta . x = 0 ;
_cursor . delta . y = 0 ;
return false ;
2004-08-09 19:04:08 +02:00
}
2006-12-29 18:16:12 +01:00
/** Check if a window can be made top-most window, and if so do
* it . If a window does not obscure any other windows , it will not
* be brought to the foreground . Also if the only obscuring windows
* are so - called system - windows , the window will not be moved .
* The function will return false when a child window of this window is a
* modal - popup ; function returns a false and child window gets a white border
* @ param w Window to bring on - top
* @ return false if the window has an active modal child , true otherwise */
2009-01-07 17:11:27 +01:00
static bool MaybeBringWindowToFront ( Window * w )
2004-08-09 19:04:08 +02:00
{
2006-12-29 18:16:12 +01:00
bool bring_to_front = false ;
2004-08-09 19:04:08 +02:00
2005-11-14 20:48:04 +01:00
if ( w - > window_class = = WC_MAIN_WINDOW | |
IsVitalWindow ( w ) | |
w - > window_class = = WC_TOOLTIPS | |
w - > window_class = = WC_DROPDOWN_MENU ) {
2006-12-29 18:16:12 +01:00
return true ;
2005-11-14 20:48:04 +01:00
}
2004-08-09 19:04:08 +02:00
2009-01-07 19:59:46 +01:00
Window * u ;
FOR_ALL_WINDOWS_FROM_BACK_FROM ( u , w - > z_front ) {
2006-12-29 18:16:12 +01:00
/* A modal child will prevent the activation of the parent window */
if ( u - > parent = = w & & ( u - > desc_flags & WDF_MODAL ) ) {
u - > flags4 | = WF_WHITE_BORDER_MASK ;
2008-05-07 00:08:18 +02:00
u - > SetDirty ( ) ;
2006-12-29 18:16:12 +01:00
return false ;
}
2006-11-18 17:47:02 +01:00
2005-11-14 20:48:04 +01:00
if ( u - > window_class = = WC_MAIN_WINDOW | |
IsVitalWindow ( u ) | |
u - > window_class = = WC_TOOLTIPS | |
u - > window_class = = WC_DROPDOWN_MENU ) {
continue ;
}
2004-08-09 19:04:08 +02:00
2006-12-29 18:16:12 +01:00
/* Window sizes don't interfere, leave z-order alone */
2004-08-09 19:04:08 +02:00
if ( w - > left + w - > width < = u - > left | |
u - > left + u - > width < = w - > left | |
w - > top + w - > height < = u - > top | |
2005-11-14 20:48:04 +01:00
u - > top + u - > height < = w - > top ) {
continue ;
}
2004-09-05 16:20:36 +02:00
2006-12-29 18:16:12 +01:00
bring_to_front = true ;
2004-08-09 19:04:08 +02:00
}
2006-12-29 18:16:12 +01:00
if ( bring_to_front ) BringWindowToFront ( w ) ;
return true ;
2004-08-09 19:04:08 +02:00
}
2006-11-15 20:35:52 +01:00
/** Handle keyboard input.
2008-05-10 15:46:36 +02:00
* @ param raw_key Lower 8 bits contain the ASCII character , the higher 16 bits the keycode
2008-04-07 22:28:58 +02:00
*/
2008-05-10 15:46:36 +02:00
void HandleKeypress ( uint32 raw_key )
2004-08-09 19:04:08 +02:00
{
2006-11-15 20:35:52 +01:00
/*
2009-03-14 19:16:29 +01:00
* During the generation of the world , there might be
* another thread that is currently building for example
* a road . To not interfere with those tasks , we should
* NOT change the _current_company here .
*
* This is not necessary either , as the only events that
* can be handled are the ' close application ' events
*/
2008-09-30 22:39:50 +02:00
if ( ! IsGeneratingWorld ( ) ) _current_company = _local_company ;
2006-11-15 20:35:52 +01:00
2007-04-06 06:10:19 +02:00
/* Setup event */
2008-05-10 15:46:36 +02:00
uint16 key = GB ( raw_key , 0 , 16 ) ;
uint16 keycode = GB ( raw_key , 16 , 16 ) ;
2004-08-09 19:04:08 +02:00
2008-01-01 19:55:15 +01:00
/*
* The Unicode standard defines an area called the private use area . Code points in this
* area are reserved for private use and thus not portable between systems . For instance ,
* Apple defines code points for the arrow keys in this area , but these are only printable
* on a system running OS X . We don ' t want these keys to show up in text fields and such ,
* and thus we have to clear the unicode character when we encounter such a key .
*/
2008-05-10 15:46:36 +02:00
if ( key > = 0xE000 & & key < = 0xF8FF ) key = 0 ;
2008-01-01 19:55:15 +01:00
/*
* If both key and keycode is zero , we don ' t bother to process the event .
*/
2008-05-10 15:46:36 +02:00
if ( key = = 0 & & keycode = = 0 ) return ;
2008-01-01 19:55:15 +01:00
2009-02-09 02:22:29 +01:00
/* Check if the focused window has a focused editbox */
if ( EditBoxInGlobalFocus ( ) ) {
/* All input will in this case go to the focused window */
2009-03-11 10:21:11 +01:00
if ( _focused_window - > OnKeyPress ( key , keycode ) = = Window : : ES_HANDLED ) return ;
2007-12-06 16:58:39 +01:00
}
2007-04-06 06:10:19 +02:00
/* Call the event, start with the uppermost window. */
2009-01-06 23:37:42 +01:00
Window * w ;
FOR_ALL_WINDOWS_FROM_FRONT ( w ) {
2008-05-18 01:11:06 +02:00
if ( w - > OnKeyPress ( key , keycode ) = = Window : : ES_HANDLED ) return ;
2004-08-09 19:04:08 +02:00
}
2005-04-03 15:35:43 +02:00
2009-01-06 23:37:42 +01:00
w = FindWindowById ( WC_MAIN_TOOLBAR , 0 ) ;
2008-05-10 15:46:36 +02:00
/* When there is no toolbar w is null, check for that */
if ( w ! = NULL ) w - > OnKeyPress ( key , keycode ) ;
2004-08-09 19:04:08 +02:00
}
2008-04-07 22:28:58 +02:00
/**
* State of CONTROL key has changed
*/
2008-02-17 18:00:43 +01:00
void HandleCtrlChanged ( )
{
/* Call the event, start with the uppermost window. */
2009-01-06 23:37:42 +01:00
Window * w ;
FOR_ALL_WINDOWS_FROM_FRONT ( w ) {
2008-05-18 01:11:06 +02:00
if ( w - > OnCTRLStateChange ( ) = = Window : : ES_HANDLED ) return ;
2008-02-17 18:00:43 +01:00
}
}
2008-04-07 22:28:58 +02:00
/**
* Local counter that is incremented each time an mouse input event is detected .
* The counter is used to stop auto - scrolling .
* @ see HandleAutoscroll ( )
* @ see HandleMouseEvents ( )
*/
2006-11-15 22:01:19 +01:00
static int _input_events_this_tick = 0 ;
2008-04-07 22:28:58 +02:00
/**
* If needed and switched on , perform auto scrolling ( automatically
* moving window contents when mouse is near edge of the window ) .
*/
2007-03-07 12:47:46 +01:00
static void HandleAutoscroll ( )
2006-11-15 22:01:19 +01:00
{
2008-05-29 17:13:28 +02:00
if ( _settings_client . gui . autoscroll & & _game_mode ! = GM_MENU & & ! IsGeneratingWorld ( ) ) {
2008-05-07 10:27:55 +02:00
int x = _cursor . pos . x ;
int y = _cursor . pos . y ;
Window * w = FindWindowFromPt ( x , y ) ;
2006-11-15 22:01:19 +01:00
if ( w = = NULL | | w - > flags4 & WF_DISABLE_VP_SCROLL ) return ;
2008-05-07 10:27:55 +02:00
ViewPort * vp = IsPtInWindowViewport ( w , x , y ) ;
2006-11-15 22:01:19 +01:00
if ( vp ! = NULL ) {
x - = vp - > left ;
y - = vp - > top ;
2008-05-07 10:27:55 +02:00
2007-04-06 06:10:19 +02:00
/* here allows scrolling in both x and y axis */
2006-11-15 22:01:19 +01:00
# define scrollspeed 3
if ( x - 15 < 0 ) {
2008-05-11 17:08:44 +02:00
w - > viewport - > dest_scrollpos_x + = ScaleByZoom ( ( x - 15 ) * scrollspeed , vp - > zoom ) ;
2006-11-15 22:01:19 +01:00
} else if ( 15 - ( vp - > width - x ) > 0 ) {
2008-05-11 17:08:44 +02:00
w - > viewport - > dest_scrollpos_x + = ScaleByZoom ( ( 15 - ( vp - > width - x ) ) * scrollspeed , vp - > zoom ) ;
2006-11-15 22:01:19 +01:00
}
if ( y - 15 < 0 ) {
2008-05-11 17:08:44 +02:00
w - > viewport - > dest_scrollpos_y + = ScaleByZoom ( ( y - 15 ) * scrollspeed , vp - > zoom ) ;
2006-11-15 22:01:19 +01:00
} else if ( 15 - ( vp - > height - y ) > 0 ) {
2008-05-11 17:08:44 +02:00
w - > viewport - > dest_scrollpos_y + = ScaleByZoom ( ( 15 - ( vp - > height - y ) ) * scrollspeed , vp - > zoom ) ;
2006-11-15 22:01:19 +01:00
}
# undef scrollspeed
}
}
}
2007-06-22 12:57:53 +02:00
enum MouseClick {
MC_NONE = 0 ,
MC_LEFT ,
MC_RIGHT ,
MC_DOUBLE_LEFT ,
2007-06-22 22:04:21 +02:00
MAX_OFFSET_DOUBLE_CLICK = 5 , ///< How much the mouse is allowed to move to call it a double click
TIME_BETWEEN_DOUBLE_CLICK = 500 , ///< Time between 2 left clicks before it becoming a double click, in ms
2007-06-22 12:57:53 +02:00
} ;
2008-04-19 15:28:48 +02:00
extern bool VpHandlePlaceSizingDrag ( ) ;
2008-05-29 12:16:59 +02:00
static void ScrollMainViewport ( int x , int y )
{
if ( _game_mode ! = GM_MENU ) {
Window * w = FindWindowById ( WC_MAIN_WINDOW , 0 ) ;
assert ( w ) ;
w - > viewport - > dest_scrollpos_x + = ScaleByZoom ( x , w - > viewport - > zoom ) ;
w - > viewport - > dest_scrollpos_y + = ScaleByZoom ( y , w - > viewport - > zoom ) ;
}
}
/**
* 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
} ;
2008-05-30 23:06:43 +02:00
static void HandleKeyScrolling ( )
2008-05-29 12:16:59 +02:00
{
2009-02-09 02:22:29 +01:00
/*
* Check that any of the dirkeys is pressed and that the focused window
* dont has an edit - box as focused widget .
*/
if ( _dirkeys & & ! EditBoxInGlobalFocus ( ) ) {
2008-05-29 12:16:59 +02:00
int factor = _shift_pressed ? 50 : 10 ;
ScrollMainViewport ( scrollamt [ _dirkeys ] [ 0 ] * factor , scrollamt [ _dirkeys ] [ 1 ] * factor ) ;
}
}
2007-06-22 12:57:53 +02:00
void MouseLoop ( MouseClick click , int mousewheel )
2004-08-09 19:04:08 +02:00
{
DecreaseWindowCounters ( ) ;
HandlePlacePresize ( ) ;
UpdateTileSelection ( ) ;
2008-05-30 23:06:43 +02:00
2005-11-14 20:48:04 +01:00
if ( ! VpHandlePlaceSizingDrag ( ) ) return ;
if ( ! HandleDragDrop ( ) ) return ;
if ( ! HandleWindowDragging ( ) ) return ;
if ( ! HandleScrollbarScrolling ( ) ) return ;
if ( ! HandleViewportScroll ( ) ) return ;
if ( ! HandleMouseOver ( ) ) return ;
2004-12-04 18:54:56 +01:00
2008-05-29 17:13:28 +02:00
bool scrollwheel_scrolling = _settings_client . gui . scrollwheel_scrolling = = 1 & & ( _cursor . v_wheel ! = 0 | | _cursor . h_wheel ! = 0 ) ;
2007-06-22 12:57:53 +02:00
if ( click = = MC_NONE & & mousewheel = = 0 & & ! scrollwheel_scrolling ) return ;
2004-08-09 19:04:08 +02:00
2008-05-07 10:27:55 +02:00
int x = _cursor . pos . x ;
int y = _cursor . pos . y ;
Window * w = FindWindowFromPt ( x , y ) ;
2005-11-14 20:48:04 +01:00
if ( w = = NULL ) return ;
2008-05-07 10:27:55 +02:00
2006-12-29 18:16:12 +01:00
if ( ! MaybeBringWindowToFront ( w ) ) return ;
2008-05-07 10:27:55 +02:00
ViewPort * vp = IsPtInWindowViewport ( w , x , y ) ;
2006-08-21 16:59:58 +02:00
/* 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 ) {
2008-05-29 17:13:28 +02:00
if ( _settings_client . gui . scrollwheel_scrolling = = 0 ) {
2008-05-17 01:30:10 +02:00
/* Send mousewheel event to window */
2008-05-10 15:46:36 +02:00
w - > OnMouseWheel ( mousewheel ) ;
2007-03-11 22:53:46 +01:00
}
2006-08-21 16:59:58 +02:00
/* Dispatch a MouseWheelEvent for widgets if it is not a viewport */
if ( vp = = NULL ) DispatchMouseWheelEvent ( w , GetWidgetFromPos ( w , x - w - > left , y - w - > top ) , mousewheel ) ;
}
2004-08-09 19:04:08 +02:00
if ( vp ! = NULL ) {
2007-06-22 12:57:53 +02:00
if ( scrollwheel_scrolling ) click = MC_RIGHT ; // we are using the scrollwheel in a viewport, so we emulate right mouse button
2006-08-21 16:59:58 +02:00
switch ( click ) {
2007-06-22 12:57:53 +02:00
case MC_DOUBLE_LEFT :
case MC_LEFT :
2006-12-26 18:36:18 +01:00
DEBUG ( misc , 2 , " Cursor: 0x%X (%d) " , _cursor . sprite , _cursor . sprite ) ;
2009-04-19 12:31:30 +02:00
if ( _thd . place_mode ! = HT_NONE & &
2007-04-06 06:10:19 +02:00
/* query button and place sign button work in pause mode */
2006-08-21 16:59:58 +02:00
_cursor . sprite ! = SPR_CURSOR_QUERY & &
_cursor . sprite ! = SPR_CURSOR_SIGN & &
2009-05-06 17:06:57 +02:00
_pause_mode ! = PM_UNPAUSED & &
2006-08-21 16:59:58 +02:00
! _cheats . build_in_pause . value ) {
return ;
}
2004-08-09 19:04:08 +02:00
2009-04-19 12:31:30 +02:00
if ( _thd . place_mode = = HT_NONE ) {
2009-01-02 23:42:05 +01:00
if ( ! HandleViewportClicked ( vp , x , y ) & &
! ( w - > flags4 & WF_DISABLE_VP_SCROLL ) & &
_settings_client . gui . left_mouse_btn_scrolling ) {
_scrolling_viewport = true ;
_cursor . fix_at = false ;
}
2006-08-21 16:59:58 +02:00
} else {
PlaceObject ( ) ;
}
break ;
2004-09-05 16:20:36 +02:00
2007-06-22 12:57:53 +02:00
case MC_RIGHT :
2006-08-21 16:59:58 +02:00
if ( ! ( w - > flags4 & WF_DISABLE_VP_SCROLL ) ) {
_scrolling_viewport = true ;
_cursor . fix_at = true ;
}
break ;
2007-06-22 12:57:53 +02:00
default :
break ;
2004-08-09 19:04:08 +02:00
}
} else {
2005-11-13 15:54:09 +01:00
switch ( click ) {
2008-05-07 23:45:27 +02:00
case MC_DOUBLE_LEFT :
DispatchLeftClickEvent ( w , x - w - > left , y - w - > top , true ) ;
if ( _mouseover_last_w = = NULL ) break ; // The window got removed.
/* fallthough, and also give a single-click for backwards compatibility */
case MC_LEFT :
DispatchLeftClickEvent ( w , x - w - > left , y - w - > top , false ) ;
break ;
2007-03-11 12:57:11 +01:00
default :
if ( ! scrollwheel_scrolling | | w = = NULL | | w - > window_class ! = WC_SMALLMAP ) break ;
/* We try to use the scrollwheel to scroll since we didn't touch any of the buttons.
2009-03-14 19:16:29 +01:00
* Simulate a right button click so we can get started . */
2007-03-11 12:57:11 +01:00
/* fallthough */
2007-06-22 12:57:53 +02:00
case MC_RIGHT : DispatchRightClickEvent ( w , x - w - > left , y - w - > top ) ; break ;
2005-11-13 15:54:09 +01:00
}
2004-08-09 19:04:08 +02:00
}
}
2008-04-07 22:28:58 +02:00
/**
* Handle a mouse event from the video driver
*/
2007-03-07 12:47:46 +01:00
void HandleMouseEvents ( )
2005-03-26 05:16:39 +01:00
{
2007-06-22 12:57:53 +02:00
static int double_click_time = 0 ;
static int double_click_x = 0 ;
static int double_click_y = 0 ;
2005-03-26 05:16:39 +01:00
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
/*
* During the generation of the world , there might be
* another thread that is currently building for example
* a road . To not interfere with those tasks , we should
2008-09-30 22:39:50 +02:00
* NOT change the _current_company here .
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 12:00:30 +02:00
*
* This is not necessary either , as the only events that
* can be handled are the ' close application ' events
*/
2008-09-30 22:39:50 +02:00
if ( ! IsGeneratingWorld ( ) ) _current_company = _local_company ;
2005-03-26 05:16:39 +01:00
2007-04-06 06:10:19 +02:00
/* Mouse event? */
2008-05-07 10:27:55 +02:00
MouseClick click = MC_NONE ;
2005-03-26 05:16:39 +01:00
if ( _left_button_down & & ! _left_button_clicked ) {
2007-06-22 12:57:53 +02:00
click = MC_LEFT ;
2007-06-22 22:04:21 +02:00
if ( double_click_time ! = 0 & & _realtime_tick - double_click_time < TIME_BETWEEN_DOUBLE_CLICK & &
2007-06-22 12:57:53 +02:00
double_click_x ! = 0 & & abs ( _cursor . pos . x - double_click_x ) < MAX_OFFSET_DOUBLE_CLICK & &
double_click_y ! = 0 & & abs ( _cursor . pos . y - double_click_y ) < MAX_OFFSET_DOUBLE_CLICK ) {
click = MC_DOUBLE_LEFT ;
}
2007-06-22 22:04:21 +02:00
double_click_time = _realtime_tick ;
2007-06-22 12:57:53 +02:00
double_click_x = _cursor . pos . x ;
double_click_y = _cursor . pos . y ;
2005-03-26 05:16:39 +01:00
_left_button_clicked = true ;
2006-11-15 22:01:19 +01:00
_input_events_this_tick + + ;
2005-03-26 05:16:39 +01:00
} else if ( _right_button_clicked ) {
_right_button_clicked = false ;
2007-06-22 12:57:53 +02:00
click = MC_RIGHT ;
2006-11-15 22:01:19 +01:00
_input_events_this_tick + + ;
2005-03-26 05:16:39 +01:00
}
2008-05-07 10:27:55 +02:00
int mousewheel = 0 ;
2005-03-26 05:16:39 +01:00
if ( _cursor . wheel ) {
mousewheel = _cursor . wheel ;
_cursor . wheel = 0 ;
2006-11-15 22:01:19 +01:00
_input_events_this_tick + + ;
2005-03-26 05:16:39 +01:00
}
MouseLoop ( click , mousewheel ) ;
}
2009-01-07 17:11:27 +01:00
/**
* Check the soft limit of deletable ( non vital , non sticky ) windows .
*/
static void CheckSoftLimit ( )
{
if ( _settings_client . gui . window_soft_limit = = 0 ) return ;
for ( ; ; ) {
uint deletable_count = 0 ;
Window * w , * last_deletable = NULL ;
FOR_ALL_WINDOWS_FROM_FRONT ( w ) {
if ( w - > window_class = = WC_MAIN_WINDOW | | IsVitalWindow ( w ) | | ( w - > flags4 & WF_STICKY ) ) continue ;
last_deletable = w ;
deletable_count + + ;
}
/* We've ot reached the soft limit yet */
if ( deletable_count < = _settings_client . gui . window_soft_limit ) break ;
assert ( last_deletable ! = NULL ) ;
delete last_deletable ;
}
}
2008-04-07 22:28:58 +02:00
/**
* Regular call from the global game loop
*/
2007-03-07 12:47:46 +01:00
void InputLoop ( )
2006-11-15 22:01:19 +01:00
{
2009-01-07 17:11:27 +01:00
CheckSoftLimit ( ) ;
2008-06-12 21:06:30 +02:00
HandleKeyScrolling ( ) ;
2009-01-04 13:09:48 +01:00
2009-01-07 19:59:46 +01:00
/* Do the actual free of the deleted windows. */
for ( Window * v = _z_front_window ; v ! = NULL ; /* nothing */ ) {
Window * w = v ;
v = v - > z_back ;
if ( w - > window_class ! = WC_INVALID ) continue ;
/* Find the window in the z-array, and effectively remove it
* by moving all windows after it one to the left . This must be
* done before removing the child so we cannot cause recursion
* between the deletion of the parent and the child . */
if ( w - > z_front = = NULL ) {
_z_front_window = w - > z_back ;
} else {
w - > z_front - > z_back = w - > z_back ;
}
if ( w - > z_back = = NULL ) {
_z_back_window = w - > z_front ;
} else {
w - > z_back - > z_front = w - > z_front ;
}
free ( w ) ;
}
2009-01-04 13:09:48 +01:00
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 ;
/* there were some inputs this tick, don't scroll ??? */
return ;
}
/* HandleMouseEvents was already called for this tick */
2006-11-15 22:01:19 +01:00
HandleMouseEvents ( ) ;
HandleAutoscroll ( ) ;
}
2008-04-07 22:28:58 +02:00
/**
* Update the continuously changing contents of the windows , such as the viewports
*/
2007-03-07 12:47:46 +01:00
void UpdateWindows ( )
2004-08-09 19:04:08 +02:00
{
2009-01-06 23:37:42 +01:00
Window * w ;
2006-11-15 20:49:16 +01:00
static int we4_timer = 0 ;
int t = we4_timer + 1 ;
2004-08-09 19:04:08 +02:00
2005-11-14 20:48:04 +01:00
if ( t > = 100 ) {
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_FRONT ( w ) {
w - > OnHundredthTick ( ) ;
2004-08-09 19:04:08 +02:00
}
t = 0 ;
}
2006-11-15 20:49:16 +01:00
we4_timer = t ;
2004-08-09 19:04:08 +02:00
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_FRONT ( w ) {
2004-08-09 19:04:08 +02:00
if ( w - > flags4 & WF_WHITE_BORDER_MASK ) {
w - > flags4 - = WF_WHITE_BORDER_ONE ;
2006-11-18 01:14:43 +01:00
2008-05-07 00:08:18 +02:00
if ( ! ( w - > flags4 & WF_WHITE_BORDER_MASK ) ) w - > SetDirty ( ) ;
2004-08-09 19:04:08 +02:00
}
}
DrawDirtyBlocks ( ) ;
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
if ( w - > viewport ! = NULL ) UpdateViewportPosition ( w ) ;
2004-08-09 19:04:08 +02:00
}
2008-08-12 00:45:11 +02:00
NetworkDrawChatMessage ( ) ;
2007-04-06 06:10:19 +02:00
/* Redraw mouse cursor in case it was hidden */
2004-08-09 19:04:08 +02:00
DrawMouseCursor ( ) ;
2004-09-05 16:20:36 +02:00
}
2004-08-09 19:04:08 +02:00
2008-04-07 22:28:58 +02:00
/**
2008-04-19 15:05:05 +02:00
* Mark window as dirty ( in need of repainting )
* @ param cls Window class
* @ param number Window number in that class
2008-04-07 22:28:58 +02:00
*/
2005-12-24 16:01:17 +01:00
void InvalidateWindow ( WindowClass cls , WindowNumber number )
2004-08-09 19:04:08 +02:00
{
2009-01-06 23:37:42 +01:00
const Window * w ;
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2008-05-07 00:08:18 +02:00
if ( w - > window_class = = cls & & w - > window_number = = number ) w - > SetDirty ( ) ;
2004-08-09 19:04:08 +02:00
}
}
2008-04-19 15:05:05 +02:00
/**
2008-04-07 22:28:58 +02:00
* Mark a particular widget in a particular window as dirty ( in need of repainting )
* @ param cls Window class
* @ param number Window number in that class
* @ param widget_index Index number of the widget that needs repainting
*/
2005-12-24 16:01:17 +01:00
void InvalidateWindowWidget ( WindowClass cls , WindowNumber number , byte widget_index )
2004-08-09 19:04:08 +02:00
{
2009-01-06 23:37:42 +01:00
const Window * w ;
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2005-11-14 20:48:04 +01:00
if ( w - > window_class = = cls & & w - > window_number = = number ) {
2007-12-07 19:05:49 +01:00
w - > InvalidateWidget ( widget_index ) ;
2004-08-09 19:04:08 +02:00
}
}
}
2008-04-19 15:05:05 +02:00
/**
2008-04-07 22:28:58 +02:00
* Mark all windows of a particular class as dirty ( in need of repainting )
* @ param cls Window class
*/
2005-12-24 16:01:17 +01:00
void InvalidateWindowClasses ( WindowClass cls )
2004-08-09 19:04:08 +02:00
{
2009-01-06 23:37:42 +01:00
Window * w ;
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
if ( w - > window_class = = cls ) w - > SetDirty ( ) ;
2004-08-09 19:04:08 +02:00
}
}
2008-04-07 22:28:58 +02:00
/**
* Mark window data as invalid ( in need of re - computing )
* @ param w Window with invalid data
*/
2008-05-10 14:30:27 +02:00
void InvalidateThisWindowData ( Window * w , int data )
2006-10-07 16:30:13 +02:00
{
2008-05-10 15:46:36 +02:00
w - > OnInvalidateData ( data ) ;
2008-05-07 00:08:18 +02:00
w - > SetDirty ( ) ;
2006-10-07 16:30:13 +02:00
}
2008-04-07 22:28:58 +02:00
/**
2008-04-19 15:05:05 +02:00
* Mark window data of the window of a given class and specific window number as invalid ( in need of re - computing )
2008-04-07 22:28:58 +02:00
* @ param cls Window class
* @ param number Window number within the class
*/
2008-05-10 14:30:27 +02:00
void InvalidateWindowData ( WindowClass cls , WindowNumber number , int data )
2006-10-05 14:59:28 +02:00
{
2009-01-06 23:37:42 +01:00
Window * w ;
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2008-05-10 14:30:27 +02:00
if ( w - > window_class = = cls & & w - > window_number = = number ) InvalidateThisWindowData ( w , data ) ;
2006-10-07 16:30:13 +02:00
}
}
2008-04-07 22:28:58 +02:00
/**
* Mark window data of all windows of a given class as invalid ( in need of re - computing )
* @ param cls Window class
*/
2008-05-10 14:30:27 +02:00
void InvalidateWindowClassesData ( WindowClass cls , int data )
2006-10-07 16:30:13 +02:00
{
2009-01-06 23:37:42 +01:00
Window * w ;
2006-10-07 16:30:13 +02:00
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
if ( w - > window_class = = cls ) InvalidateThisWindowData ( w , data ) ;
2006-10-05 14:59:28 +02:00
}
}
2004-08-09 19:04:08 +02:00
2008-04-07 22:28:58 +02:00
/**
* Dispatch WE_TICK event over all windows
*/
2007-03-07 12:47:46 +01:00
void CallWindowTickEvent ( )
2004-08-09 19:04:08 +02:00
{
2008-05-29 12:16:59 +02:00
if ( _scroller_click_timeout > 3 ) {
_scroller_click_timeout - = 3 ;
} else {
_scroller_click_timeout = 0 ;
}
2009-01-06 23:37:42 +01:00
Window * w ;
FOR_ALL_WINDOWS_FROM_FRONT ( w ) {
w - > OnTick ( ) ;
2004-08-09 19:04:08 +02:00
}
}
2008-04-19 15:28:48 +02:00
/**
* Try to delete a non - vital window .
* Non - vital windows are windows other than the game selection , main toolbar ,
* status bar , toolbar menu , and tooltip windows . Stickied windows are also
* considered vital .
*/
2007-03-07 12:47:46 +01:00
void DeleteNonVitalWindows ( )
2004-08-09 19:04:08 +02:00
{
2009-01-06 23:37:42 +01:00
Window * w ;
2005-11-14 20:48:04 +01:00
2006-11-18 01:44:09 +01:00
restart_search :
/* When we find the window to delete, we need to restart the search
2006-11-18 17:47:02 +01:00
* as deleting this window could cascade in deleting ( many ) others
* anywhere in the z - array */
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2004-08-09 19:04:08 +02:00
if ( w - > window_class ! = WC_MAIN_WINDOW & &
w - > window_class ! = WC_SELECT_GAME & &
w - > window_class ! = WC_MAIN_TOOLBAR & &
w - > window_class ! = WC_STATUS_BAR & &
w - > window_class ! = WC_TOOLBAR_MENU & &
2004-12-16 00:33:04 +01:00
w - > window_class ! = WC_TOOLTIPS & &
( w - > flags4 & WF_STICKY ) = = 0 ) { // do not delete windows which are 'pinned'
2006-11-18 17:47:02 +01:00
2008-05-06 23:28:30 +02:00
delete w ;
2006-11-18 01:44:09 +01:00
goto restart_search ;
2004-08-09 19:04:08 +02:00
}
}
}
2007-04-09 17:06:24 +02:00
/** It is possible that a stickied window gets to a position where the
2004-12-22 18:37:21 +01:00
* ' close ' button is outside the gaming area . You cannot close it then ; except
* with this function . It closes all windows calling the standard function ,
* then , does a little hacked loop of closing all stickied windows . Note
* that standard windows ( status bar , etc . ) are not stickied , so these aren ' t affected */
2007-03-07 12:47:46 +01:00
void DeleteAllNonVitalWindows ( )
2004-12-22 18:37:21 +01:00
{
2009-01-06 23:37:42 +01:00
Window * w ;
2005-11-14 20:48:04 +01:00
2006-11-18 01:44:09 +01:00
/* Delete every window except for stickied ones, then sticky ones as well */
2004-12-22 18:37:21 +01:00
DeleteNonVitalWindows ( ) ;
2006-11-18 17:47:02 +01:00
2006-11-18 01:44:09 +01:00
restart_search :
/* When we find the window to delete, we need to restart the search
2006-11-18 17:47:02 +01:00
* as deleting this window could cascade in deleting ( many ) others
* anywhere in the z - array */
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
if ( w - > flags4 & WF_STICKY ) {
delete w ;
2006-11-18 01:44:09 +01:00
goto restart_search ;
2006-06-27 23:25:53 +02:00
}
2004-12-22 18:37:21 +01:00
}
}
2009-02-04 17:59:41 +01:00
/**
* Delete all windows that are used for construction of vehicle etc .
* Once done with that invalidate the others to ensure they get refreshed too .
*/
void DeleteConstructionWindows ( )
{
Window * w ;
restart_search :
/* When we find the window to delete, we need to restart the search
* as deleting this window could cascade in deleting ( many ) others
* anywhere in the z - array */
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
if ( w - > desc_flags & WDF_CONSTRUCTION ) {
delete w ;
goto restart_search ;
}
}
FOR_ALL_WINDOWS_FROM_BACK ( w ) w - > SetDirty ( ) ;
}
2007-04-09 17:06:24 +02:00
/** Delete all always on-top windows to get an empty screen */
2007-03-07 12:47:46 +01:00
void HideVitalWindows ( )
2005-01-11 01:54:06 +01:00
{
2007-02-02 15:32:23 +01:00
DeleteWindowById ( WC_TOOLBAR_MENU , 0 ) ;
2005-01-11 01:54:06 +01:00
DeleteWindowById ( WC_MAIN_TOOLBAR , 0 ) ;
DeleteWindowById ( WC_STATUS_BAR , 0 ) ;
}
2009-06-28 22:09:40 +02:00
/** Re-initialize all windows. */
void ReInitAllWindows ( )
{
Window * w ;
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
w - > ReInit ( ) ;
}
}
2008-04-07 22:28:58 +02:00
/**
* ( Re ) position main toolbar window at the screen
* @ param w Window structure of the main toolbar window , may also be \ c NULL
* @ return X coordinate of left edge of the repositioned toolbar window
*/
2004-09-05 16:20:36 +02:00
int PositionMainToolbar ( Window * w )
2004-08-16 23:02:06 +02:00
{
2006-12-26 18:36:18 +01:00
DEBUG ( misc , 5 , " Repositioning Main Toolbar... " ) ;
2004-08-16 23:02:06 +02:00
2006-06-27 23:25:53 +02:00
if ( w = = NULL | | w - > window_class ! = WC_MAIN_TOOLBAR ) {
2004-08-16 23:02:06 +02:00
w = FindWindowById ( WC_MAIN_TOOLBAR , 0 ) ;
2006-06-27 23:25:53 +02:00
}
2004-08-16 23:02:06 +02:00
2008-05-29 17:13:28 +02:00
switch ( _settings_client . gui . toolbar_pos ) {
2006-11-11 10:47:44 +01:00
case 1 : w - > left = ( _screen . width - w - > width ) / 2 ; break ;
2005-07-09 00:25:24 +02:00
case 2 : w - > left = _screen . width - w - > width ; break ;
default : w - > left = 0 ;
2004-08-16 23:02:06 +02:00
}
SetDirtyBlocks ( 0 , 0 , _screen . width , w - > height ) ; // invalidate the whole top part
return w - > left ;
}
2009-01-03 11:52:22 +01:00
/**
* Set the number of items of the vertical scrollbar .
*
* Function also updates the position of the scrollbar if necessary .
* @ param w Window containing the vertical scrollbar
* @ param num New number of items
*/
2008-05-29 08:49:56 +02:00
void SetVScrollCount ( Window * w , int num )
{
w - > vscroll . count = num ;
num - = w - > vscroll . cap ;
if ( num < 0 ) num = 0 ;
if ( num < w - > vscroll . pos ) w - > vscroll . pos = num ;
}
2009-01-03 11:52:22 +01:00
/**
* Set the number of items of the second vertical scrollbar .
*
* Function also updates the position of the scrollbar if necessary .
* @ param w Window containing the second vertical scrollbar
* @ param num New number of items
*/
2008-05-29 08:49:56 +02:00
void SetVScroll2Count ( Window * w , int num )
{
w - > vscroll2 . count = num ;
num - = w - > vscroll2 . cap ;
if ( num < 0 ) num = 0 ;
if ( num < w - > vscroll2 . pos ) w - > vscroll2 . pos = num ;
}
2009-01-03 11:52:22 +01:00
/**
* Set the number of items of the horizontal scrollbar .
*
* Function also updates the position of the scrollbar if necessary .
* @ param w Window containing the horizontal scrollbar
* @ param num New number of items
*/
2008-05-29 08:49:56 +02:00
void SetHScrollCount ( Window * w , int num )
{
w - > hscroll . count = num ;
num - = w - > hscroll . cap ;
if ( num < 0 ) num = 0 ;
if ( num < w - > hscroll . pos ) w - > hscroll . pos = num ;
}
2008-04-07 22:28:58 +02:00
/**
* Relocate all windows to fit the new size of the game application screen
* @ param neww New width of the game application screen
* @ param newh New height of the game appliction screen
*/
2004-08-09 19:04:08 +02:00
void RelocateAllWindows ( int neww , int newh )
{
2009-01-06 23:37:42 +01:00
Window * w ;
2004-08-09 19:04:08 +02:00
2009-01-06 23:37:42 +01:00
FOR_ALL_WINDOWS_FROM_BACK ( w ) {
2004-08-09 19:04:08 +02:00
int left , top ;
2004-09-05 16:20:36 +02:00
2004-08-09 19:04:08 +02:00
if ( w - > window_class = = WC_MAIN_WINDOW ) {
ViewPort * vp = w - > viewport ;
vp - > width = w - > width = neww ;
vp - > height = w - > height = newh ;
2007-05-15 18:08:46 +02:00
vp - > virtual_width = ScaleByZoom ( neww , vp - > zoom ) ;
vp - > virtual_height = ScaleByZoom ( newh , vp - > zoom ) ;
2004-08-09 19:04:08 +02:00
continue ; // don't modify top,left
2004-09-03 21:59:05 +02:00
}
2006-11-18 18:07:05 +01:00
/* XXX - this probably needs something more sane. For example specying
* in a ' backup ' - desc that the window should always be centred . */
2006-02-06 10:18:04 +01:00
switch ( w - > window_class ) {
case WC_MAIN_TOOLBAR :
2007-07-29 21:18:22 +02:00
if ( neww - w - > width ! = 0 ) {
ResizeWindow ( w , min ( neww , 640 ) - w - > width , 0 ) ;
2008-05-10 15:46:36 +02:00
Point delta ;
delta . x = neww - w - > width ;
delta . y = 0 ;
2009-03-29 11:49:11 +02:00
w - > OnResize ( delta ) ;
2007-07-29 21:18:22 +02:00
}
2006-02-06 10:18:04 +01:00
top = w - > top ;
left = PositionMainToolbar ( w ) ; // changes toolbar orientation
break ;
case WC_SELECT_GAME :
case WC_GAME_OPTIONS :
case WC_NETWORK_WINDOW :
top = ( newh - w - > height ) > > 1 ;
left = ( neww - w - > width ) > > 1 ;
break ;
case WC_NEWS_WINDOW :
top = newh - w - > height ;
left = ( neww - w - > width ) > > 1 ;
break ;
case WC_STATUS_BAR :
2007-11-19 19:38:10 +01:00
ResizeWindow ( w , Clamp ( neww , 320 , 640 ) - w - > width , 0 ) ;
2006-02-06 10:18:04 +01:00
top = newh - w - > height ;
left = ( neww - w - > width ) > > 1 ;
break ;
case WC_SEND_NETWORK_MSG :
2007-11-19 19:38:10 +01:00
ResizeWindow ( w , Clamp ( neww , 320 , 640 ) - w - > width , 0 ) ;
2006-02-06 10:18:04 +01:00
top = ( newh - 26 ) ; // 26 = height of status bar + height of chat bar
left = ( neww - w - > width ) > > 1 ;
break ;
2006-11-18 18:07:05 +01:00
case WC_CONSOLE :
2006-11-21 23:10:52 +01:00
IConsoleResize ( w ) ;
2006-11-19 23:24:18 +01:00
continue ;
2006-11-18 18:07:05 +01:00
2008-03-15 21:32:42 +01:00
default : {
2006-02-06 10:18:04 +01:00
left = w - > left ;
if ( left + ( w - > width > > 1 ) > = neww ) left = neww - w - > width ;
2007-12-06 21:55:48 +01:00
if ( left < 0 ) left = 0 ;
2006-02-06 10:18:04 +01:00
top = w - > top ;
if ( top + ( w - > height > > 1 ) > = newh ) top = newh - w - > height ;
2008-03-15 21:32:42 +01:00
const Window * wt = FindWindowById ( WC_MAIN_TOOLBAR , 0 ) ;
if ( wt ! = NULL ) {
2008-04-15 01:26:31 +02:00
if ( top < wt - > height & & wt - > left < ( w - > left + w - > width ) & & ( wt - > left + wt - > width ) > w - > left ) top = wt - > height ;
2008-03-15 21:32:42 +01:00
if ( top > = newh ) top = newh - 1 ;
} else {
if ( top < 0 ) top = 0 ;
}
} break ;
2004-08-09 19:04:08 +02:00
}
2005-11-14 20:48:04 +01:00
if ( w - > viewport ! = NULL ) {
2004-08-09 19:04:08 +02:00
w - > viewport - > left + = left - w - > left ;
w - > viewport - > top + = top - w - > top ;
}
w - > left = left ;
w - > top = top ;
}
}
2008-05-17 05:29:16 +02:00
/** Destructor of the base class PickerWindowBase
* Main utility is to stop the base Window destructor from triggering
* a free while the child will already be free , in this case by the ResetObjectToPlace ( ) .
*/
PickerWindowBase : : ~ PickerWindowBase ( )
{
this - > window_class = WC_INVALID ; // stop the ancestor from freeing the already (to be) child
ResetObjectToPlace ( ) ;
}