(svn r538) -Feature: Windows snap at each other
authortron
Wed, 10 Nov 2004 21:14:16 +0000
changeset 350 67a59a1226b5
parent 349 47cdc8ab9cf7
child 351 0395322c6278
(svn r538) -Feature: Windows snap at each other
This is inspired by [1063636].
lang/english.txt
lang/german.txt
settings.c
settings_gui.c
variables.h
window.c
--- a/lang/english.txt	Mon Nov 08 22:21:14 2004 +0000
+++ b/lang/english.txt	Wed Nov 10 21:14:16 2004 +0000
@@ -1040,6 +1040,8 @@
 STR_CONFIG_PATCHES_TOOLBAR_POS_LEFT		:Left
 STR_CONFIG_PATCHES_TOOLBAR_POS_CENTER	:Centre
 STR_CONFIG_PATCHES_TOOLBAR_POS_RIGHT	:Right
+STR_CONFIG_PATCHES_SNAP_RADIUS			:{LTBLUE}Window snap radius: {ORANGE}{STRING} px
+STR_CONFIG_PATCHES_SNAP_RADIUS_DISABLED	:{LTBLUE}Window snap radius: {ORANGE}disabled
 
 STR_CONFIG_PATCHES_GUI					:{BLACK}Interface
 STR_CONFIG_PATCHES_CONSTRUCTION			:{BLACK}Construction
--- a/lang/german.txt	Mon Nov 08 22:21:14 2004 +0000
+++ b/lang/german.txt	Wed Nov 10 21:14:16 2004 +0000
@@ -1040,6 +1040,8 @@
 STR_CONFIG_PATCHES_TOOLBAR_POS_LEFT				:Links
 STR_CONFIG_PATCHES_TOOLBAR_POS_CENTER				:Mitte
 STR_CONFIG_PATCHES_TOOLBAR_POS_RIGHT				:Rechts
+STR_CONFIG_PATCHES_SNAP_RADIUS					:{LTBLUE}Fenster schnappen aneinander, wenn näher als: {ORANGE}{STRING} px
+STR_CONFIG_PATCHES_SNAP_RADIUS_DISABLED				:{LTBLUE}Fenster schnappen aneinander, wenn näher als: {ORANGE}ausgeschaltet
 
 STR_CONFIG_PATCHES_GUI						:{BLACK}Oberfläche
 STR_CONFIG_PATCHES_CONSTRUCTION					:{BLACK}Konstruktion
--- a/settings.c	Mon Nov 08 22:21:14 2004 +0000
+++ b/settings.c	Wed Nov 10 21:14:16 2004 +0000
@@ -829,6 +829,7 @@
 	{"realistic_acceleration",SDT_BOOL, (void*)false, (void*)offsetof(Patches, realistic_acceleration),	NULL},
 
 	{"toolbar_pos",					SDT_UINT8,	(void*)0,			(void*)offsetof(Patches, toolbar_pos),					NULL},
+	{"window_snap_radius",  SDT_UINT8,  (void*)10,    (void*)offsetof(Patches, window_snap_radius),   NULL},
 
 	{"max_trains",					SDT_UINT8,	(void*)80,		(void*)offsetof(Patches, max_trains),						NULL},
 	{"max_roadveh",					SDT_UINT8,	(void*)80,		(void*)offsetof(Patches, max_roadveh),					NULL},
--- a/settings_gui.c	Mon Nov 08 22:21:14 2004 +0000
+++ b/settings_gui.c	Wed Nov 10 21:14:16 2004 +0000
@@ -572,6 +572,7 @@
 	{PE_UINT8,	0, STR_CONFIG_PATCHES_ERRMSG_DURATION,	&_patches.errmsg_duration,					0, 20,  1, NULL},
 
 	{PE_UINT8,	PF_MULTISTRING, STR_CONFIG_PATCHES_TOOLBAR_POS, &_patches.toolbar_pos,			0,  2,  1, &v_PositionMainToolbar},
+	{PE_UINT8, PF_0ISDIS, STR_CONFIG_PATCHES_SNAP_RADIUS, &_patches.window_snap_radius,     1, 32,  1, NULL},
 	{PE_BOOL,		0, STR_CONFIG_PATCHES_INVISIBLE_TREES,	&_patches.invisible_trees,					0,  1,  1, &InvisibleTreesActive},
 };
 
--- a/variables.h	Mon Nov 08 22:21:14 2004 +0000
+++ b/variables.h	Wed Nov 10 21:14:16 2004 +0000
@@ -114,6 +114,7 @@
 	bool invisible_trees; // don't show trees when buildings are transparent
 
 	uint8 toolbar_pos;			// position of toolbars, 0=left, 1=center, 2=right
+	uint8 window_snap_radius; // Windows snap at each other if closer than this
 
 	byte max_trains;				//max trains in game per player (these are 8bit because the unitnumber field can't hold more)
 	byte max_roadveh;				//max trucks in game per player
--- a/window.c	Mon Nov 08 22:21:14 2004 +0000
+++ b/window.c	Wed Nov 10 21:14:16 2004 +0000
@@ -5,6 +5,9 @@
 #include "viewport.h"
 #include "console.h"
 
+// delta between mouse cursor and upper left corner of dragged window
+static Point _drag_delta;
+
 void HandleButtonClick(Window *w, byte widget)
 {
 	w->click_state |= (1 << widget);
@@ -691,50 +694,116 @@
 bool HandleWindowDragging()
 {
 	Window *w;
-	int x, y, t;
-
 	// Get out immediately if no window is being dragged at all.
 	if (!_dragging_window)
 		return true;
 
 	// Otherwise find the window...
-	for(w=_windows; w != _last_window; w++) {
-		if (w->flags4&(WF_DRAGGING|WF_SIZING)) {
+	for (w = _windows; w != _last_window; w++) {
+		if (w->flags4 & WF_DRAGGING) {
+			const Window *v;
+			int x;
+			int y;
+			int nx;
+			int ny;
 
 			// Stop the dragging if the left mouse button was released
 			if (!_left_button_down) {
-				w->flags4 &= ~(WF_DRAGGING | WF_SIZING);
+				w->flags4 &= ~WF_DRAGGING;
 				break;
 			}
 
-			// Otherwise calculate the delta position.
-			x = _cursor.pos.x;
-			y = clamp2(_cursor.pos.y, 23, _screen.height-12);
-			t = _cursorpos_drag_start.x; _cursorpos_drag_start.x = x; x-=t;
-			t = _cursorpos_drag_start.y; _cursorpos_drag_start.y = y; y-=t;
-
-			// No movement?
-			if (x == 0 && y == 0)
-				return false;
-
-			// Mark the old position dirty
 			SetWindowDirty(w);
 
-			if (w->flags4 & WF_SIZING) {
-				// Size the window
-				w->width += x;
-				w->height += y;
-			} else {
-				// Move the window and viewport
-				w->left += x;
-				w->top += y;
-				if (w->viewport) {
-					w->viewport->left += x;
-					w->viewport->top += y;
+			x = _cursor.pos.x + _drag_delta.x;
+			y = _cursor.pos.y + _drag_delta.y;
+			nx = x;
+			ny = y;
+
+			if (_patches.window_snap_radius != 0) {
+				uint hsnap = _patches.window_snap_radius;
+				uint vsnap = _patches.window_snap_radius;
+				uint delta;
+
+				// Snap at screen borders
+				// Left screen border
+				delta = abs(x);
+				if (delta <= hsnap) {
+					nx = 0;
+					hsnap = delta;
+				}
+
+				// Right screen border
+				delta = abs(_screen.width - x - w->width);
+				if (delta <= hsnap) {
+					nx = _screen.width - w->width;
+					hsnap = delta;
+				}
+
+				// Top of screen
+				delta = abs(y);
+				if (delta <= vsnap) {
+					ny = 0;
+					vsnap = delta;
+				}
+
+				// Bottom of screen
+				delta = abs(_screen.height - y - w->height);
+				if (delta <= vsnap) {
+					ny = _screen.height - w->height;
+					vsnap = delta;
+				}
+
+				// Snap at other windows
+				for (v = _windows; v != _last_window; ++v) {
+					if (v == w) continue; // Don't snap at yourself
+
+					if (y + w->height > v->top && y < v->top + v->height) {
+						// Your left border <-> other right border
+						delta = abs(v->left + v->width - x);
+						if (delta <= hsnap) {
+							nx = v->left + v->width;
+							hsnap = delta;
+						}
+
+						// Your right border <-> other left border
+						delta = abs(v->left - x - w->width);
+						if (delta <= hsnap) {
+							nx = v->left - w->width;
+							hsnap = delta;
+						}
+					}
+
+					if (x + w->width > v->left && x < v->left + v->width) {
+						// Your top border <-> other bottom border
+						delta = abs(v->top + v->height - y);
+						if (delta <= vsnap) {
+							ny = v->top + v->height;
+							vsnap = delta;
+						}
+
+						// Your bottom border <-> other top border
+						delta = abs(v->top - y - w->height);
+						if (delta <= vsnap) {
+							ny = v->top - w->height;
+							vsnap = delta;
+						}
+					}
 				}
 			}
 
-			// And also mark the new position dirty.
+			// Make sure the window doesn't leave the screen
+			// 13 is the height of the title bar
+			nx = clamp(nx, 13 - w->width, _screen.width - 13);
+			ny = clamp(ny, 0, _screen.height - 13);
+
+			if (w->viewport != NULL) {
+				w->viewport->left += nx - w->left;
+				w->viewport->top  += ny - w->top;
+			}
+			w->left = nx;
+			w->top  = ny;
+
 			SetWindowDirty(w);
 			return false;
 		}
@@ -748,7 +817,8 @@
 {
 	w->flags4 |= WF_DRAGGING;
 	_dragging_window = true;
-	_cursorpos_drag_start = _cursor.pos;
+	_drag_delta.x = w->left - _cursor.pos.x;
+	_drag_delta.y = w->top  - _cursor.pos.y;
 	w = BringWindowToFront(w);
 	DeleteWindowById(WC_DROPDOWN_MENU, 0);
 	return w;