src/window.cpp
branchgamebalance
changeset 9908 0fa543611bbe
parent 9895 7bd07f43b0e3
child 9909 dce9a6923bb7
equal deleted inserted replaced
9907:3b068c3a1c74 9908:0fa543611bbe
    16 #include "variables.h"
    16 #include "variables.h"
    17 #include "table/sprites.h"
    17 #include "table/sprites.h"
    18 #include "genworld.h"
    18 #include "genworld.h"
    19 #include "helpers.hpp"
    19 #include "helpers.hpp"
    20 
    20 
    21 // delta between mouse cursor and upper left corner of dragged window
    21 /* delta between mouse cursor and upper left corner of dragged window */
    22 static Point _drag_delta;
    22 static Point _drag_delta;
    23 
    23 
    24 static Window _windows[25];
    24 static Window _windows[25];
    25 Window *_z_windows[lengthof(_windows)];
    25 Window *_z_windows[lengthof(_windows)];
    26 Window **_last_z_window; ///< always points to the next free space in the z-array
    26 Window **_last_z_window; ///< always points to the next free space in the z-array
    99 	e.we.click.pt.y = y;
    99 	e.we.click.pt.y = y;
   100 	e.event = WE_CLICK;
   100 	e.event = WE_CLICK;
   101 
   101 
   102 	if (w->desc_flags & WDF_DEF_WIDGET) {
   102 	if (w->desc_flags & WDF_DEF_WIDGET) {
   103 		e.we.click.widget = GetWidgetFromPos(w, x, y);
   103 		e.we.click.widget = GetWidgetFromPos(w, x, y);
   104 		if (e.we.click.widget < 0) return; /* exit if clicked outside of widgets */
   104 		if (e.we.click.widget < 0) return; // exit if clicked outside of widgets
   105 
   105 
   106 		/* don't allow any interaction if the button has been disabled */
   106 		/* don't allow any interaction if the button has been disabled */
   107 		if (IsWindowWidgetDisabled(w, e.we.click.widget)) return;
   107 		if (IsWindowWidgetDisabled(w, e.we.click.widget)) return;
   108 
   108 
   109 		wi = &w->widget[e.we.click.widget];
   109 		wi = &w->widget[e.we.click.widget];
   155 
   155 
   156 	/* default tooltips handler? */
   156 	/* default tooltips handler? */
   157 	if (w->desc_flags & WDF_STD_TOOLTIPS) {
   157 	if (w->desc_flags & WDF_STD_TOOLTIPS) {
   158 		e.we.click.widget = GetWidgetFromPos(w, x, y);
   158 		e.we.click.widget = GetWidgetFromPos(w, x, y);
   159 		if (e.we.click.widget < 0)
   159 		if (e.we.click.widget < 0)
   160 			return; /* exit if clicked outside of widgets */
   160 			return; // exit if clicked outside of widgets
   161 
   161 
   162 		if (w->widget[e.we.click.widget].tooltips != 0) {
   162 		if (w->widget[e.we.click.widget].tooltips != 0) {
   163 			GuiShowTooltips(w->widget[e.we.click.widget].tooltips);
   163 			GuiShowTooltips(w->widget[e.we.click.widget].tooltips);
   164 			return;
   164 			return;
   165 		}
   165 		}
   289 	if (w == NULL) return;
   289 	if (w == NULL) return;
   290 	SetDirtyBlocks(w->left, w->top, w->left + w->width, w->top + w->height);
   290 	SetDirtyBlocks(w->left, w->top, w->left + w->width, w->top + w->height);
   291 }
   291 }
   292 
   292 
   293 /** Find the Window whose parent pointer points to this window
   293 /** Find the Window whose parent pointer points to this window
   294  * @parent w Window to find child of
   294  * @param w parent Window to find child of
   295  * @return return a Window pointer that is the child of w, or NULL otherwise */
   295  * @return a Window pointer that is the child of w, or NULL otherwise */
   296 static Window *FindChildWindow(const Window *w)
   296 static Window *FindChildWindow(const Window *w)
   297 {
   297 {
   298 	Window* const *wz;
   298 	Window* const *wz;
   299 
   299 
   300 	FOR_ALL_WINDOWS(wz) {
   300 	FOR_ALL_WINDOWS(wz) {
   304 
   304 
   305 	return NULL;
   305 	return NULL;
   306 }
   306 }
   307 
   307 
   308 /** Find the z-value of a window. A window must already be open
   308 /** Find the z-value of a window. A window must already be open
   309  * or the behaviour is undefined but function should never fail */
   309  * or the behaviour is undefined but function should never fail
       
   310  * @param w window to query Z Position
       
   311  * @return the window that matches it */
   310 Window **FindWindowZPosition(const Window *w)
   312 Window **FindWindowZPosition(const Window *w)
   311 {
   313 {
   312 	Window **wz;
   314 	Window **wz;
   313 
   315 
   314 	for (wz = _z_windows; wz != _last_z_window; wz++) {
   316 	for (wz = _z_windows; wz != _last_z_window; wz++) {
   439 }
   441 }
   440 
   442 
   441 static void BringWindowToFront(const Window *w);
   443 static void BringWindowToFront(const Window *w);
   442 
   444 
   443 /** Find a window and make it the top-window on the screen. The window
   445 /** Find a window and make it the top-window on the screen. The window
   444  * gets a white border for a brief period of time to visualize its
   446  * gets a white border for a brief period of time to visualize its "activation"
   445  * "activation"
   447  * @param cls WindowClass of the window to activate
       
   448  * @param number WindowNumber of the window to activate
   446  * @return a pointer to the window thus activated */
   449  * @return a pointer to the window thus activated */
   447 Window *BringWindowToFrontById(WindowClass cls, WindowNumber number)
   450 Window *BringWindowToFrontById(WindowClass cls, WindowNumber number)
   448 {
   451 {
   449 	Window *w = FindWindowById(cls, number);
   452 	Window *w = FindWindowById(cls, number);
   450 
   453 
   533 bool IsWindowOfPrototype(const Window *w, const Widget *widget)
   536 bool IsWindowOfPrototype(const Window *w, const Widget *widget)
   534 {
   537 {
   535 	return (w->original_widget == widget);
   538 	return (w->original_widget == widget);
   536 }
   539 }
   537 
   540 
   538 /* Copies 'widget' to 'w->widget' to allow for resizable windows */
   541 /** Copies 'widget' to 'w->widget' to allow for resizable windows
       
   542  * @param w Window on which to attach the widget array
       
   543  * @param widget pointer of widget array to fill the window with */
   539 void AssignWidgetToWindow(Window *w, const Widget *widget)
   544 void AssignWidgetToWindow(Window *w, const Widget *widget)
   540 {
   545 {
   541 	w->original_widget = widget;
   546 	w->original_widget = widget;
   542 
   547 
   543 	if (widget != NULL) {
   548 	if (widget != NULL) {
   575 
   580 
   576 	assert(_last_z_window == endof(_z_windows));
   581 	assert(_last_z_window == endof(_z_windows));
   577 	return NULL;
   582 	return NULL;
   578 }
   583 }
   579 
   584 
   580 /* Open a new window.
   585 /** Open a new window.
   581  * This function is called from AllocateWindow() or AllocateWindowDesc()
   586  * This function is called from AllocateWindow() or AllocateWindowDesc()
   582  * See descriptions for those functions for usage
   587  * See descriptions for those functions for usage
   583  * See AllocateWindow() for description of arguments.
   588  * See AllocateWindow() for description of arguments.
   584  * Only addition here is window_number, which is the window_number being assigned to the new window
   589  * Only addition here is window_number, which is the window_number being assigned to the new window
   585  */
   590  * @param x offset in pixels from the left of the screen
       
   591  * @param y offset in pixels from the top of the screen
       
   592  * @param width width in pixels of the window
       
   593  * @param height height in pixels of the window
       
   594  * @param *proc see WindowProc function to call when any messages/updates happen to the window
       
   595  * @param cls see WindowClass class of the window, used for identification and grouping
       
   596  * @param *widget see Widget pointer to the window layout and various elements
       
   597  * @param window_number number being assigned to the new window
       
   598  * @return Window pointer of the newly created window */
   586 static Window *LocalAllocateWindow(
   599 static Window *LocalAllocateWindow(
   587 							int x, int y, int width, int height,
   600 							int x, int y, int width, int height,
   588 							WindowProc *proc, WindowClass cls, const Widget *widget, int window_number)
   601 							WindowProc *proc, WindowClass cls, const Widget *widget, int window_number)
   589 {
   602 {
   590 	Window *w = FindFreeWindow();
   603 	Window *w = FindFreeWindow();
   594 		w = FindDeletableWindow();
   607 		w = FindDeletableWindow();
   595 		if (w == NULL) w = ForceFindDeletableWindow();
   608 		if (w == NULL) w = ForceFindDeletableWindow();
   596 		DeleteWindow(w);
   609 		DeleteWindow(w);
   597 	}
   610 	}
   598 
   611 
   599 	// Set up window properties
   612 	/* Set up window properties */
   600 	memset(w, 0, sizeof(*w));
   613 	memset(w, 0, sizeof(*w));
   601 	w->window_class = cls;
   614 	w->window_class = cls;
   602 	w->flags4 = WF_WHITE_BORDER_MASK; // just opened windows have a white border
   615 	w->flags4 = WF_WHITE_BORDER_MASK; // just opened windows have a white border
   603 	w->caption_color = 0xFF;
   616 	w->caption_color = 0xFF;
   604 	w->left = x;
   617 	w->left = x;
   651  * ones. Finally set all variables and call the WE_CREATE event
   664  * ones. Finally set all variables and call the WE_CREATE event
   652  * @param x offset in pixels from the left of the screen
   665  * @param x offset in pixels from the left of the screen
   653  * @param y offset in pixels from the top of the screen
   666  * @param y offset in pixels from the top of the screen
   654  * @param width width in pixels of the window
   667  * @param width width in pixels of the window
   655  * @param height height in pixels of the window
   668  * @param height height in pixels of the window
   656  * @param *proc @see WindowProc function to call when any messages/updates happen to the window
   669  * @param *proc see WindowProc function to call when any messages/updates happen to the window
   657  * @param cls @see WindowClass class of the window, used for identification and grouping
   670  * @param cls see WindowClass class of the window, used for identification and grouping
   658  * @param *widget @see Widget pointer to the window layout and various elements
   671  * @param *widget see Widget pointer to the window layout and various elements
   659  * @return @see Window pointer of the newly created window
   672  * @return Window pointer of the newly created window */
   660  */
       
   661 Window *AllocateWindow(
   673 Window *AllocateWindow(
   662 							int x, int y, int width, int height,
   674 							int x, int y, int width, int height,
   663 							WindowProc *proc, WindowClass cls, const Widget *widget)
   675 							WindowProc *proc, WindowClass cls, const Widget *widget)
   664 {
   676 {
   665 	return LocalAllocateWindow(x, y, width, height, proc, cls, widget, 0);
   677 	return LocalAllocateWindow(x, y, width, height, proc, cls, widget, 0);
   683 	bottom = _awap_r.height + top;
   695 	bottom = _awap_r.height + top;
   684 
   696 
   685 	if (left < 0 || top < 22 || right > _screen.width || bottom > _screen.height)
   697 	if (left < 0 || top < 22 || right > _screen.width || bottom > _screen.height)
   686 		return false;
   698 		return false;
   687 
   699 
   688 	// Make sure it is not obscured by any window.
   700 	/* Make sure it is not obscured by any window. */
   689 	FOR_ALL_WINDOWS(wz) {
   701 	FOR_ALL_WINDOWS(wz) {
   690 		const Window *w = *wz;
   702 		const Window *w = *wz;
   691 		if (w->window_class == WC_MAIN_WINDOW) continue;
   703 		if (w->window_class == WC_MAIN_WINDOW) continue;
   692 
   704 
   693 		if (right > w->left &&
   705 		if (right > w->left &&
   712 	height = _awap_r.height;
   724 	height = _awap_r.height;
   713 
   725 
   714 	if (left < -(width>>2) || left > _screen.width - (width>>1)) return false;
   726 	if (left < -(width>>2) || left > _screen.width - (width>>1)) return false;
   715 	if (top < 22 || top > _screen.height - (height>>2)) return false;
   727 	if (top < 22 || top > _screen.height - (height>>2)) return false;
   716 
   728 
   717 	// Make sure it is not obscured by any window.
   729 	/* Make sure it is not obscured by any window. */
   718 	FOR_ALL_WINDOWS(wz) {
   730 	FOR_ALL_WINDOWS(wz) {
   719 		const Window *w = *wz;
   731 		const Window *w = *wz;
   720 		if (w->window_class == WC_MAIN_WINDOW) continue;
   732 		if (w->window_class == WC_MAIN_WINDOW) continue;
   721 
   733 
   722 		if (left + width > w->left &&
   734 		if (left + width > w->left &&
   850 }
   862 }
   851 
   863 
   852 /**
   864 /**
   853  * Open a new window.
   865  * Open a new window.
   854  * @param *desc The pointer to the WindowDesc to be created
   866  * @param *desc The pointer to the WindowDesc to be created
   855  * @return @see Window pointer of the newly created window
   867  * @return Window pointer of the newly created window
   856  */
   868  */
   857 Window *AllocateWindowDesc(const WindowDesc *desc)
   869 Window *AllocateWindowDesc(const WindowDesc *desc)
   858 {
   870 {
   859 	return LocalAllocateWindowDesc(desc, 0);
   871 	return LocalAllocateWindowDesc(desc, 0);
   860 }
   872 }
   861 
   873 
   862 /**
   874 /**
   863  * Open a new window.
   875  * Open a new window.
   864  * @param *desc The pointer to the WindowDesc to be created
   876  * @param *desc The pointer to the WindowDesc to be created
   865  * @param window_number the window number of the new window
   877  * @param window_number the window number of the new window
   866  * @return @see Window pointer of the newly created window
   878  * @return see Window pointer of the newly created window
   867  */
   879  */
   868 Window *AllocateWindowDescFront(const WindowDesc *desc, int window_number)
   880 Window *AllocateWindowDescFront(const WindowDesc *desc, int window_number)
   869 {
   881 {
   870 	Window *w;
   882 	Window *w;
   871 
   883 
   874 	return w;
   886 	return w;
   875 }
   887 }
   876 
   888 
   877 /** Do a search for a window at specific coordinates. For this we start
   889 /** Do a search for a window at specific coordinates. For this we start
   878  * at the topmost window, obviously and work our way down to the bottom
   890  * at the topmost window, obviously and work our way down to the bottom
       
   891  * @param x position x to query
       
   892  * @param y position y to query
   879  * @return a pointer to the found window if any, NULL otherwise */
   893  * @return a pointer to the found window if any, NULL otherwise */
   880 Window *FindWindowFromPt(int x, int y)
   894 Window *FindWindowFromPt(int x, int y)
   881 {
   895 {
   882 	Window* const *wz;
   896 	Window* const *wz;
   883 
   897 
   934 	Window *w;
   948 	Window *w;
   935 	Window* const *wz;
   949 	Window* const *wz;
   936 
   950 
   937 	for (wz = _last_z_window; wz != _z_windows;) {
   951 	for (wz = _last_z_window; wz != _z_windows;) {
   938 		w = *--wz;
   952 		w = *--wz;
   939 		// Unclick scrollbar buttons if they are pressed.
   953 		/* Unclick scrollbar buttons if they are pressed. */
   940 		if (w->flags4 & (WF_SCROLL_DOWN | WF_SCROLL_UP)) {
   954 		if (w->flags4 & (WF_SCROLL_DOWN | WF_SCROLL_UP)) {
   941 			w->flags4 &= ~(WF_SCROLL_DOWN | WF_SCROLL_UP);
   955 			w->flags4 &= ~(WF_SCROLL_DOWN | WF_SCROLL_UP);
   942 			SetWindowDirty(w);
   956 			SetWindowDirty(w);
   943 		}
   957 		}
   944 		CallWindowEventNP(w, WE_MOUSELOOP);
   958 		CallWindowEventNP(w, WE_MOUSELOOP);
   991 	w = GetCallbackWnd();
  1005 	w = GetCallbackWnd();
   992 
  1006 
   993 	ResetObjectToPlace();
  1007 	ResetObjectToPlace();
   994 
  1008 
   995 	if (w != NULL) {
  1009 	if (w != NULL) {
   996 		// send an event in client coordinates.
  1010 		/* send an event in client coordinates. */
   997 		e.event = WE_DRAGDROP;
  1011 		e.event = WE_DRAGDROP;
   998 		e.we.dragdrop.pt.x = _cursor.pos.x - w->left;
  1012 		e.we.dragdrop.pt.x = _cursor.pos.x - w->left;
   999 		e.we.dragdrop.pt.y = _cursor.pos.y - w->top;
  1013 		e.we.dragdrop.pt.y = _cursor.pos.y - w->top;
  1000 		e.we.dragdrop.widget = GetWidgetFromPos(w, e.we.dragdrop.pt.x, e.we.dragdrop.pt.y);
  1014 		e.we.dragdrop.widget = GetWidgetFromPos(w, e.we.dragdrop.pt.x, e.we.dragdrop.pt.y);
  1001 		w->wndproc(w, &e);
  1015 		w->wndproc(w, &e);
  1036 	WindowEvent e;
  1050 	WindowEvent e;
  1037 	static Window *last_w = NULL;
  1051 	static Window *last_w = NULL;
  1038 
  1052 
  1039 	w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
  1053 	w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y);
  1040 
  1054 
  1041 	// We changed window, put a MOUSEOVER event to the last window
  1055 	/* We changed window, put a MOUSEOVER event to the last window */
  1042 	if (last_w != NULL && last_w != w) {
  1056 	if (last_w != NULL && last_w != w) {
  1043 		e.event = WE_MOUSEOVER;
  1057 		e.event = WE_MOUSEOVER;
  1044 		e.we.mouseover.pt.x = -1;
  1058 		e.we.mouseover.pt.x = -1;
  1045 		e.we.mouseover.pt.y = -1;
  1059 		e.we.mouseover.pt.y = -1;
  1046 		if (last_w->wndproc) last_w->wndproc(last_w, &e);
  1060 		if (last_w->wndproc) last_w->wndproc(last_w, &e);
  1047 	}
  1061 	}
  1048 	last_w = w;
  1062 	last_w = w;
  1049 
  1063 
  1050 	if (w != NULL) {
  1064 	if (w != NULL) {
  1051 		// send an event in client coordinates.
  1065 		/* send an event in client coordinates. */
  1052 		e.event = WE_MOUSEOVER;
  1066 		e.event = WE_MOUSEOVER;
  1053 		e.we.mouseover.pt.x = _cursor.pos.x - w->left;
  1067 		e.we.mouseover.pt.x = _cursor.pos.x - w->left;
  1054 		e.we.mouseover.pt.y = _cursor.pos.y - w->top;
  1068 		e.we.mouseover.pt.y = _cursor.pos.y - w->top;
  1055 		if (w->widget != NULL) {
  1069 		if (w->widget != NULL) {
  1056 			e.we.mouseover.widget = GetWidgetFromPos(w, e.we.mouseover.pt.x, e.we.mouseover.pt.y);
  1070 			e.we.mouseover.widget = GetWidgetFromPos(w, e.we.mouseover.pt.x, e.we.mouseover.pt.y);
  1057 		}
  1071 		}
  1058 		w->wndproc(w, &e);
  1072 		w->wndproc(w, &e);
  1059 	}
  1073 	}
  1060 
  1074 
  1061 	// Mouseover never stops execution
  1075 	/* Mouseover never stops execution */
  1062 	return true;
  1076 	return true;
  1063 }
  1077 }
  1064 
  1078 
  1065 /** Update all the widgets of a window based on their resize flags
  1079 /** Update all the widgets of a window based on their resize flags
  1066  * Both the areas of the old window and the new sized window are set dirty
  1080  * Both the areas of the old window and the new sized window are set dirty
  1115 static bool _dragging_window;
  1129 static bool _dragging_window;
  1116 
  1130 
  1117 static bool HandleWindowDragging()
  1131 static bool HandleWindowDragging()
  1118 {
  1132 {
  1119 	Window* const *wz;
  1133 	Window* const *wz;
  1120 	// Get out immediately if no window is being dragged at all.
  1134 	/* Get out immediately if no window is being dragged at all. */
  1121 	if (!_dragging_window) return true;
  1135 	if (!_dragging_window) return true;
  1122 
  1136 
  1123 	// Otherwise find the window...
  1137 	/* Otherwise find the window... */
  1124 	FOR_ALL_WINDOWS(wz) {
  1138 	FOR_ALL_WINDOWS(wz) {
  1125 		Window *w = *wz;
  1139 		Window *w = *wz;
  1126 
  1140 
  1127 		if (w->flags4 & WF_DRAGGING) {
  1141 		if (w->flags4 & WF_DRAGGING) {
  1128 			const Widget *t = &w->widget[1]; // the title bar ... ugh
  1142 			const Widget *t = &w->widget[1]; // the title bar ... ugh
  1130 			int x;
  1144 			int x;
  1131 			int y;
  1145 			int y;
  1132 			int nx;
  1146 			int nx;
  1133 			int ny;
  1147 			int ny;
  1134 
  1148 
  1135 			// Stop the dragging if the left mouse button was released
  1149 			/* Stop the dragging if the left mouse button was released */
  1136 			if (!_left_button_down) {
  1150 			if (!_left_button_down) {
  1137 				w->flags4 &= ~WF_DRAGGING;
  1151 				w->flags4 &= ~WF_DRAGGING;
  1138 				break;
  1152 				break;
  1139 			}
  1153 			}
  1140 
  1154 
  1156 					const Window *v = *vz;
  1170 					const Window *v = *vz;
  1157 
  1171 
  1158 					if (v == w) continue; // Don't snap at yourself
  1172 					if (v == w) continue; // Don't snap at yourself
  1159 
  1173 
  1160 					if (y + w->height > v->top && y < v->top + v->height) {
  1174 					if (y + w->height > v->top && y < v->top + v->height) {
  1161 						// Your left border <-> other right border
  1175 						/* Your left border <-> other right border */
  1162 						delta = abs(v->left + v->width - x);
  1176 						delta = abs(v->left + v->width - x);
  1163 						if (delta <= hsnap) {
  1177 						if (delta <= hsnap) {
  1164 							nx = v->left + v->width;
  1178 							nx = v->left + v->width;
  1165 							hsnap = delta;
  1179 							hsnap = delta;
  1166 						}
  1180 						}
  1167 
  1181 
  1168 						// Your right border <-> other left border
  1182 						/* Your right border <-> other left border */
  1169 						delta = abs(v->left - x - w->width);
  1183 						delta = abs(v->left - x - w->width);
  1170 						if (delta <= hsnap) {
  1184 						if (delta <= hsnap) {
  1171 							nx = v->left - w->width;
  1185 							nx = v->left - w->width;
  1172 							hsnap = delta;
  1186 							hsnap = delta;
  1173 						}
  1187 						}
  1174 					}
  1188 					}
  1175 
  1189 
  1176 					if (w->top + w->height >= v->top && w->top <= v->top + v->height) {
  1190 					if (w->top + w->height >= v->top && w->top <= v->top + v->height) {
  1177 						// Your left border <-> other left border
  1191 						/* Your left border <-> other left border */
  1178 						delta = abs(v->left - x);
  1192 						delta = abs(v->left - x);
  1179 						if (delta <= hsnap) {
  1193 						if (delta <= hsnap) {
  1180 							nx = v->left;
  1194 							nx = v->left;
  1181 							hsnap = delta;
  1195 							hsnap = delta;
  1182 						}
  1196 						}
  1183 
  1197 
  1184 						// Your right border <-> other right border
  1198 						/* Your right border <-> other right border */
  1185 						delta = abs(v->left + v->width - x - w->width);
  1199 						delta = abs(v->left + v->width - x - w->width);
  1186 						if (delta <= hsnap) {
  1200 						if (delta <= hsnap) {
  1187 							nx = v->left + v->width - w->width;
  1201 							nx = v->left + v->width - w->width;
  1188 							hsnap = delta;
  1202 							hsnap = delta;
  1189 						}
  1203 						}
  1190 					}
  1204 					}
  1191 
  1205 
  1192 					if (x + w->width > v->left && x < v->left + v->width) {
  1206 					if (x + w->width > v->left && x < v->left + v->width) {
  1193 						// Your top border <-> other bottom border
  1207 						/* Your top border <-> other bottom border */
  1194 						delta = abs(v->top + v->height - y);
  1208 						delta = abs(v->top + v->height - y);
  1195 						if (delta <= vsnap) {
  1209 						if (delta <= vsnap) {
  1196 							ny = v->top + v->height;
  1210 							ny = v->top + v->height;
  1197 							vsnap = delta;
  1211 							vsnap = delta;
  1198 						}
  1212 						}
  1199 
  1213 
  1200 						// Your bottom border <-> other top border
  1214 						/* Your bottom border <-> other top border */
  1201 						delta = abs(v->top - y - w->height);
  1215 						delta = abs(v->top - y - w->height);
  1202 						if (delta <= vsnap) {
  1216 						if (delta <= vsnap) {
  1203 							ny = v->top - w->height;
  1217 							ny = v->top - w->height;
  1204 							vsnap = delta;
  1218 							vsnap = delta;
  1205 						}
  1219 						}
  1206 					}
  1220 					}
  1207 
  1221 
  1208 					if (w->left + w->width >= v->left && w->left <= v->left + v->width) {
  1222 					if (w->left + w->width >= v->left && w->left <= v->left + v->width) {
  1209 						// Your top border <-> other top border
  1223 						/* Your top border <-> other top border */
  1210 						delta = abs(v->top - y);
  1224 						delta = abs(v->top - y);
  1211 						if (delta <= vsnap) {
  1225 						if (delta <= vsnap) {
  1212 							ny = v->top;
  1226 							ny = v->top;
  1213 							vsnap = delta;
  1227 							vsnap = delta;
  1214 						}
  1228 						}
  1215 
  1229 
  1216 						// Your bottom border <-> other bottom border
  1230 						/* Your bottom border <-> other bottom border */
  1217 						delta = abs(v->top + v->height - y - w->height);
  1231 						delta = abs(v->top + v->height - y - w->height);
  1218 						if (delta <= vsnap) {
  1232 						if (delta <= vsnap) {
  1219 							ny = v->top + v->height - w->height;
  1233 							ny = v->top + v->height - w->height;
  1220 							vsnap = delta;
  1234 							vsnap = delta;
  1221 						}
  1235 						}
  1222 					}
  1236 					}
  1223 				}
  1237 				}
  1224 			}
  1238 			}
  1225 
  1239 
  1226 			// Make sure the window doesn't leave the screen
  1240 			/* Make sure the window doesn't leave the screen
  1227 			// 13 is the height of the title bar
  1241 			 * 13 is the height of the title bar */
  1228 			nx = clamp(nx, 13 - t->right, _screen.width - 13 - t->left);
  1242 			nx = clamp(nx, 13 - t->right, _screen.width - 13 - t->left);
  1229 			ny = clamp(ny, 0, _screen.height - 13);
  1243 			ny = clamp(ny, 0, _screen.height - 13);
  1230 
  1244 
  1231 			// Make sure the title bar isn't hidden by behind the main tool bar
  1245 			/* Make sure the title bar isn't hidden by behind the main tool bar */
  1232 			v = FindWindowById(WC_MAIN_TOOLBAR, 0);
  1246 			v = FindWindowById(WC_MAIN_TOOLBAR, 0);
  1233 			if (v != NULL) {
  1247 			if (v != NULL) {
  1234 				int v_bottom = v->top + v->height;
  1248 				int v_bottom = v->top + v->height;
  1235 				int v_right = v->left + v->width;
  1249 				int v_right = v->left + v->width;
  1236 				if (ny + t->top >= v->top && ny + t->top < v_bottom) {
  1250 				if (ny + t->top >= v->top && ny + t->top < v_bottom) {
  1343 	Window* const *wz;
  1357 	Window* const *wz;
  1344 	int i;
  1358 	int i;
  1345 	int pos;
  1359 	int pos;
  1346 	Scrollbar *sb;
  1360 	Scrollbar *sb;
  1347 
  1361 
  1348 	// Get out quickly if no item is being scrolled
  1362 	/* Get out quickly if no item is being scrolled */
  1349 	if (!_scrolling_scrollbar) return true;
  1363 	if (!_scrolling_scrollbar) return true;
  1350 
  1364 
  1351 	// Find the scrolling window
  1365 	/* Find the scrolling window */
  1352 	FOR_ALL_WINDOWS(wz) {
  1366 	FOR_ALL_WINDOWS(wz) {
  1353 		Window *w = *wz;
  1367 		Window *w = *wz;
  1354 
  1368 
  1355 		if (w->flags4 & WF_SCROLL_MIDDLE) {
  1369 		if (w->flags4 & WF_SCROLL_MIDDLE) {
  1356 			// Abort if no button is clicked any more.
  1370 			/* Abort if no button is clicked any more. */
  1357 			if (!_left_button_down) {
  1371 			if (!_left_button_down) {
  1358 				w->flags4 &= ~WF_SCROLL_MIDDLE;
  1372 				w->flags4 &= ~WF_SCROLL_MIDDLE;
  1359 				SetWindowDirty(w);
  1373 				SetWindowDirty(w);
  1360 				break;
  1374 				break;
  1361 			}
  1375 			}
  1369 			} else {
  1383 			} else {
  1370 				sb = &w->vscroll;
  1384 				sb = &w->vscroll;
  1371 				i = _cursor.pos.y - _cursorpos_drag_start.y;
  1385 				i = _cursor.pos.y - _cursorpos_drag_start.y;
  1372 			}
  1386 			}
  1373 
  1387 
  1374 			// Find the item we want to move to and make sure it's inside bounds.
  1388 			/* Find the item we want to move to and make sure it's inside bounds. */
  1375 			pos = min(max(0, i + _scrollbar_start_pos) * sb->count / _scrollbar_size, max(0, sb->count - sb->cap));
  1389 			pos = min(max(0, i + _scrollbar_start_pos) * sb->count / _scrollbar_size, max(0, sb->count - sb->cap));
  1376 			if (pos != sb->pos) {
  1390 			if (pos != sb->pos) {
  1377 				sb->pos = pos;
  1391 				sb->pos = pos;
  1378 				SetWindowDirty(w);
  1392 				SetWindowDirty(w);
  1379 			}
  1393 			}
  1480 	if (bring_to_front) BringWindowToFront(w);
  1494 	if (bring_to_front) BringWindowToFront(w);
  1481 	return true;
  1495 	return true;
  1482 }
  1496 }
  1483 
  1497 
  1484 /** Send a message from one window to another. The receiving window is found by
  1498 /** Send a message from one window to another. The receiving window is found by
  1485  * @param w @see Window pointer pointing to the other window
  1499  * @param w Window pointer pointing to the other window
  1486  * @param msg Specifies the message to be sent
  1500  * @param msg Specifies the message to be sent
  1487  * @param wparam Specifies additional message-specific information
  1501  * @param wparam Specifies additional message-specific information
  1488  * @param lparam Specifies additional message-specific information
  1502  * @param lparam Specifies additional message-specific information
  1489  */
  1503  */
  1490 static void SendWindowMessageW(Window *w, uint msg, uint wparam, uint lparam)
  1504 static void SendWindowMessageW(Window *w, uint msg, uint wparam, uint lparam)
  1498 
  1512 
  1499 	w->wndproc(w, &e);
  1513 	w->wndproc(w, &e);
  1500 }
  1514 }
  1501 
  1515 
  1502 /** Send a message from one window to another. The receiving window is found by
  1516 /** Send a message from one window to another. The receiving window is found by
  1503  * @param wnd_class @see WindowClass class AND
  1517  * @param wnd_class see WindowClass class AND
  1504  * @param wnd_num @see WindowNumber number, mostly 0
  1518  * @param wnd_num see WindowNumber number, mostly 0
  1505  * @param msg Specifies the message to be sent
  1519  * @param msg Specifies the message to be sent
  1506  * @param wparam Specifies additional message-specific information
  1520  * @param wparam Specifies additional message-specific information
  1507  * @param lparam Specifies additional message-specific information
  1521  * @param lparam Specifies additional message-specific information
  1508  */
  1522  */
  1509 void SendWindowMessage(WindowClass wnd_class, WindowNumber wnd_num, int msg, int wparam, int lparam)
  1523 void SendWindowMessage(WindowClass wnd_class, WindowNumber wnd_num, int msg, int wparam, int lparam)
  1512 	if (w != NULL) SendWindowMessageW(w, msg, wparam, lparam);
  1526 	if (w != NULL) SendWindowMessageW(w, msg, wparam, lparam);
  1513 }
  1527 }
  1514 
  1528 
  1515 /** Send a message from one window to another. The message will be sent
  1529 /** Send a message from one window to another. The message will be sent
  1516  * to ALL windows of the windowclass specified in the first parameter
  1530  * to ALL windows of the windowclass specified in the first parameter
  1517  * @param wnd_class @see WindowClass class
  1531  * @param wnd_class see WindowClass class
  1518  * @param msg Specifies the message to be sent
  1532  * @param msg Specifies the message to be sent
  1519  * @param wparam Specifies additional message-specific information
  1533  * @param wparam Specifies additional message-specific information
  1520  * @param lparam Specifies additional message-specific information
  1534  * @param lparam Specifies additional message-specific information
  1521  */
  1535  */
  1522 void SendWindowMessageClass(WindowClass wnd_class, int msg, int wparam, int lparam)
  1536 void SendWindowMessageClass(WindowClass wnd_class, int msg, int wparam, int lparam)
  1549 	* This is not necessary either, as the only events that
  1563 	* This is not necessary either, as the only events that
  1550 	* can be handled are the 'close application' events
  1564 	* can be handled are the 'close application' events
  1551 	*/
  1565 	*/
  1552 	if (!IsGeneratingWorld()) _current_player = _local_player;
  1566 	if (!IsGeneratingWorld()) _current_player = _local_player;
  1553 
  1567 
  1554 	// Setup event
  1568 	/* Setup event */
  1555 	e.event = WE_KEYPRESS;
  1569 	e.event = WE_KEYPRESS;
  1556 	e.we.keypress.key     = GB(key,  0, 16);
  1570 	e.we.keypress.key     = GB(key,  0, 16);
  1557 	e.we.keypress.keycode = GB(key, 16, 16);
  1571 	e.we.keypress.keycode = GB(key, 16, 16);
  1558 	e.we.keypress.cont = true;
  1572 	e.we.keypress.cont = true;
  1559 
  1573 
  1560 	// check if we have a query string window open before allowing hotkeys
  1574 	/* check if we have a query string window open before allowing hotkeys */
  1561 	if (FindWindowById(WC_QUERY_STRING,       0) != NULL ||
  1575 	if (FindWindowById(WC_QUERY_STRING,       0) != NULL ||
  1562 			FindWindowById(WC_SEND_NETWORK_MSG,   0) != NULL ||
  1576 			FindWindowById(WC_SEND_NETWORK_MSG,   0) != NULL ||
  1563 			FindWindowById(WC_GENERATE_LANDSCAPE, 0) != NULL ||
  1577 			FindWindowById(WC_GENERATE_LANDSCAPE, 0) != NULL ||
  1564 			FindWindowById(WC_CONSOLE,            0) != NULL ||
  1578 			FindWindowById(WC_CONSOLE,            0) != NULL ||
  1565 			FindWindowById(WC_SAVELOAD,           0) != NULL) {
  1579 			FindWindowById(WC_SAVELOAD,           0) != NULL) {
  1566 		query_open = true;
  1580 		query_open = true;
  1567 	}
  1581 	}
  1568 
  1582 
  1569 	// Call the event, start with the uppermost window.
  1583 	/* Call the event, start with the uppermost window. */
  1570 	for (wz = _last_z_window; wz != _z_windows;) {
  1584 	for (wz = _last_z_window; wz != _z_windows;) {
  1571 		Window *w = *--wz;
  1585 		Window *w = *--wz;
  1572 
  1586 
  1573 		// if a query window is open, only call the event for certain window types
  1587 		/* if a query window is open, only call the event for certain window types */
  1574 		if (query_open &&
  1588 		if (query_open &&
  1575 				w->window_class != WC_QUERY_STRING &&
  1589 				w->window_class != WC_QUERY_STRING &&
  1576 				w->window_class != WC_SEND_NETWORK_MSG &&
  1590 				w->window_class != WC_SEND_NETWORK_MSG &&
  1577 				w->window_class != WC_GENERATE_LANDSCAPE &&
  1591 				w->window_class != WC_GENERATE_LANDSCAPE &&
  1578 				w->window_class != WC_CONSOLE &&
  1592 				w->window_class != WC_CONSOLE &&
  1583 		if (!e.we.keypress.cont) break;
  1597 		if (!e.we.keypress.cont) break;
  1584 	}
  1598 	}
  1585 
  1599 
  1586 	if (e.we.keypress.cont) {
  1600 	if (e.we.keypress.cont) {
  1587 		Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
  1601 		Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
  1588 		// When there is no toolbar w is null, check for that
  1602 		/* When there is no toolbar w is null, check for that */
  1589 		if (w != NULL) w->wndproc(w, &e);
  1603 		if (w != NULL) w->wndproc(w, &e);
  1590 	}
  1604 	}
  1591 }
  1605 }
  1592 
  1606 
  1593 extern void UpdateTileSelection();
  1607 extern void UpdateTileSelection();
  1614 		if (w == NULL || w->flags4 & WF_DISABLE_VP_SCROLL) return;
  1628 		if (w == NULL || w->flags4 & WF_DISABLE_VP_SCROLL) return;
  1615 		vp = IsPtInWindowViewport(w, x, y);
  1629 		vp = IsPtInWindowViewport(w, x, y);
  1616 		if (vp != NULL) {
  1630 		if (vp != NULL) {
  1617 			x -= vp->left;
  1631 			x -= vp->left;
  1618 			y -= vp->top;
  1632 			y -= vp->top;
  1619 			//here allows scrolling in both x and y axis
  1633 			/* here allows scrolling in both x and y axis */
  1620 #define scrollspeed 3
  1634 #define scrollspeed 3
  1621 			if (x - 15 < 0) {
  1635 			if (x - 15 < 0) {
  1622 				WP(w, vp_d).scrollpos_x += (x - 15) * scrollspeed << vp->zoom;
  1636 				WP(w, vp_d).scrollpos_x += (x - 15) * scrollspeed << vp->zoom;
  1623 			} else if (15 - (vp->width - x) > 0) {
  1637 			} else if (15 - (vp->width - x) > 0) {
  1624 				WP(w, vp_d).scrollpos_x += (15 - (vp->width - x)) * scrollspeed << vp->zoom;
  1638 				WP(w, vp_d).scrollpos_x += (15 - (vp->width - x)) * scrollspeed << vp->zoom;
  1683 		if (scrollwheel_scrolling) click = 2; // we are using the scrollwheel in a viewport, so we emulate right mouse button
  1697 		if (scrollwheel_scrolling) click = 2; // we are using the scrollwheel in a viewport, so we emulate right mouse button
  1684 		switch (click) {
  1698 		switch (click) {
  1685 			case 1:
  1699 			case 1:
  1686 				DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite);
  1700 				DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite);
  1687 				if (_thd.place_mode != 0 &&
  1701 				if (_thd.place_mode != 0 &&
  1688 						// query button and place sign button work in pause mode
  1702 						/* query button and place sign button work in pause mode */
  1689 						_cursor.sprite != SPR_CURSOR_QUERY &&
  1703 						_cursor.sprite != SPR_CURSOR_QUERY &&
  1690 						_cursor.sprite != SPR_CURSOR_SIGN &&
  1704 						_cursor.sprite != SPR_CURSOR_SIGN &&
  1691 						_pause_game != 0 &&
  1705 						_pause_game != 0 &&
  1692 						!_cheats.build_in_pause.value) {
  1706 						!_cheats.build_in_pause.value) {
  1693 					return;
  1707 					return;
  1734 	 * This is not necessary either, as the only events that
  1748 	 * This is not necessary either, as the only events that
  1735 	 * can be handled are the 'close application' events
  1749 	 * can be handled are the 'close application' events
  1736 	 */
  1750 	 */
  1737 	if (!IsGeneratingWorld()) _current_player = _local_player;
  1751 	if (!IsGeneratingWorld()) _current_player = _local_player;
  1738 
  1752 
  1739 	// Mouse event?
  1753 	/* Mouse event? */
  1740 	click = 0;
  1754 	click = 0;
  1741 	if (_left_button_down && !_left_button_clicked) {
  1755 	if (_left_button_down && !_left_button_clicked) {
  1742 		_left_button_clicked = true;
  1756 		_left_button_clicked = true;
  1743 		click = 1;
  1757 		click = 1;
  1744 		_input_events_this_tick++;
  1758 		_input_events_this_tick++;
  1791 
  1805 
  1792 	FOR_ALL_WINDOWS(wz) {
  1806 	FOR_ALL_WINDOWS(wz) {
  1793 		if ((*wz)->viewport != NULL) UpdateViewportPosition(*wz);
  1807 		if ((*wz)->viewport != NULL) UpdateViewportPosition(*wz);
  1794 	}
  1808 	}
  1795 	DrawTextMessage();
  1809 	DrawTextMessage();
  1796 	// Redraw mouse cursor in case it was hidden
  1810 	/* Redraw mouse cursor in case it was hidden */
  1797 	DrawMouseCursor();
  1811 	DrawMouseCursor();
  1798 }
  1812 }
  1799 
  1813 
  1800 
  1814 
  1801 int GetMenuItemIndex(const Window *w, int x, int y)
  1815 int GetMenuItemIndex(const Window *w, int x, int y)
  1908 			goto restart_search;
  1922 			goto restart_search;
  1909 		}
  1923 		}
  1910 	}
  1924 	}
  1911 }
  1925 }
  1912 
  1926 
  1913 /* It is possible that a stickied window gets to a position where the
  1927 /** It is possible that a stickied window gets to a position where the
  1914  * 'close' button is outside the gaming area. You cannot close it then; except
  1928  * 'close' button is outside the gaming area. You cannot close it then; except
  1915  * with this function. It closes all windows calling the standard function,
  1929  * with this function. It closes all windows calling the standard function,
  1916  * then, does a little hacked loop of closing all stickied windows. Note
  1930  * then, does a little hacked loop of closing all stickied windows. Note
  1917  * that standard windows (status bar, etc.) are not stickied, so these aren't affected */
  1931  * that standard windows (status bar, etc.) are not stickied, so these aren't affected */
  1918 void DeleteAllNonVitalWindows()
  1932 void DeleteAllNonVitalWindows()
  1932 			goto restart_search;
  1946 			goto restart_search;
  1933 		}
  1947 		}
  1934 	}
  1948 	}
  1935 }
  1949 }
  1936 
  1950 
  1937 /* Delete all always on-top windows to get an empty screen */
  1951 /** Delete all always on-top windows to get an empty screen */
  1938 void HideVitalWindows()
  1952 void HideVitalWindows()
  1939 {
  1953 {
  1940 	DeleteWindowById(WC_TOOLBAR_MENU, 0);
  1954 	DeleteWindowById(WC_TOOLBAR_MENU, 0);
  1941 	DeleteWindowById(WC_MAIN_TOOLBAR, 0);
  1955 	DeleteWindowById(WC_MAIN_TOOLBAR, 0);
  1942 	DeleteWindowById(WC_STATUS_BAR, 0);
  1956 	DeleteWindowById(WC_STATUS_BAR, 0);