Changeset - r7464:e57bd91228a2
[Not reviewed]
master
0 1 0
truelight - 17 years ago 2007-08-23 11:08:59
truelight@openttd.org
(svn r10967) -Fix: in case of moving the window on create (because it doesn't fit in the screen), make sure to move the viewport too if we are an extra viewport (spotted by Maedhros)
1 file changed with 13 insertions and 3 deletions:
0 comments (0 inline, 0 general)
src/window.cpp
Show inline comments
 
@@ -600,197 +600,207 @@ static Window *FindFreeWindow()
 
 * @param window_number number being assigned to the new window
 
 * @param data the data to be given during the WE_CREATE message
 
 * @return Window pointer of the newly created window */
 
static Window *LocalAllocateWindow(
 
							int x, int y, int min_width, int min_height, int def_width, int def_height,
 
							WindowProc *proc, WindowClass cls, const Widget *widget, int window_number, void *data)
 
{
 
	Window *w = FindFreeWindow();
 

	
 
	/* We have run out of windows, close one and use that as the place for our new one */
 
	if (w == NULL) {
 
		w = FindDeletableWindow();
 
		if (w == NULL) w = ForceFindDeletableWindow();
 
		DeleteWindow(w);
 
	}
 

	
 
	/* Set up window properties */
 
	memset(w, 0, sizeof(*w));
 
	w->window_class = cls;
 
	w->flags4 = WF_WHITE_BORDER_MASK; // just opened windows have a white border
 
	w->caption_color = 0xFF;
 
	w->left = x;
 
	w->top = y;
 
	w->width = min_width;
 
	w->height = min_height;
 
	w->wndproc = proc;
 
	AssignWidgetToWindow(w, widget);
 
	w->resize.width = min_width;
 
	w->resize.height = min_height;
 
	w->resize.step_width = 1;
 
	w->resize.step_height = 1;
 
	w->window_number = window_number;
 

	
 
	{
 
		Window **wz = _last_z_window;
 

	
 
		/* Hacky way of specifying always-on-top windows. These windows are
 
		 * 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 */
 
		if (wz != _z_windows && w->window_class != WC_SEND_NETWORK_MSG && w->window_class != WC_HIGHSCORE && w->window_class != WC_ENDSCREEN) {
 
			if (FindWindowById(WC_MAIN_TOOLBAR, 0)     != NULL) wz--;
 
			if (FindWindowById(WC_STATUS_BAR, 0)       != NULL) wz--;
 
			if (FindWindowById(WC_NEWS_WINDOW, 0)      != NULL) wz--;
 
			if (FindWindowById(WC_SEND_NETWORK_MSG, 0) != NULL) wz--;
 

	
 
			assert(wz >= _z_windows);
 
			if (wz != _last_z_window) memmove(wz + 1, wz, (byte*)_last_z_window - (byte*)wz);
 
		}
 

	
 
		*wz = w;
 
		_last_z_window++;
 
	}
 

	
 
	WindowEvent e;
 
	e.event = WE_CREATE;
 
	e.we.create.data = data;
 
	w->wndproc(w, &e);
 

	
 
	/* 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. */
 
	if (w->width != def_width || w->height != def_height) {
 
		/* 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;
 

	
 
		int enlarge_x = max(min(def_width  - w->width,  _screen.width - w->width),  0);
 
		int enlarge_y = max(min(def_height - w->height, free_height   - w->height), 0);
 

	
 
		/* 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. */
 
		if (w->resize.step_width  > 1) enlarge_x -= enlarge_x % (int)w->resize.step_width;
 
		if (w->resize.step_height > 1) enlarge_y -= enlarge_y % (int)w->resize.step_height;
 

	
 
		ResizeWindow(w, enlarge_x, enlarge_y);
 

	
 
		WindowEvent e;
 
		e.event = WE_RESIZE;
 
		e.we.sizing.size.x = w->width;
 
		e.we.sizing.size.y = w->height;
 
		e.we.sizing.diff.x = enlarge_x;
 
		e.we.sizing.diff.y = enlarge_y;
 
		w->wndproc(w, &e);
 
	}
 

	
 
	if (w->left + w->width > _screen.width) w->left -= (w->left + w->width - _screen.width);
 
	int nx = w->left;
 
	int ny = w->top;
 

	
 
	if (nx + w->width > _screen.width) nx -= (nx + w->width - _screen.width);
 

	
 
	const Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0);
 
	w->top  = max(w->top, (wt == NULL || w == wt || y == 0) ? 0 : wt->height);
 
	w->left = max(w->left, 0);
 
	ny = max(ny, (wt == NULL || w == wt || y == 0) ? 0 : wt->height);
 
	nx = max(nx, 0);
 

	
 
	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 w;
 
}
 

	
 
/**
 
 * 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
 
 * @param *proc see WindowProc function to call when any messages/updates happen to the window
 
 * @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
 
 * @return Window pointer of the newly created window */
 
Window *AllocateWindow(
 
							int x, int y, int width, int height,
 
							WindowProc *proc, WindowClass cls, const Widget *widget, void *data)
 
{
 
	return LocalAllocateWindow(x, y, width, height, width, height, proc, cls, widget, 0, data);
 
}
 

	
 
struct SizeRect {
 
	int left,top,width,height;
 
};
 

	
 

	
 
static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &pos)
 
{
 
	Window* const *wz;
 

	
 
	int right  = width + left;
 
	int bottom = height + top;
 

	
 
	if (left < 0 || top < 22 || right > _screen.width || bottom > _screen.height)
 
		return false;
 

	
 
	/* Make sure it is not obscured by any window. */
 
	FOR_ALL_WINDOWS(wz) {
 
		const Window *w = *wz;
 
		if (w->window_class == WC_MAIN_WINDOW) continue;
 

	
 
		if (right > w->left &&
 
				w->left + w->width > left &&
 
				bottom > w->top &&
 
				w->top + w->height > top) {
 
			return false;
 
		}
 
	}
 

	
 
	pos.x = left;
 
	pos.y = top;
 
	return true;
 
}
 

	
 
static bool IsGoodAutoPlace2(int left, int top, int width, int height, Point &pos)
 
{
 
	Window* const *wz;
 

	
 
	if (left < -(width>>2) || left > _screen.width - (width>>1)) return false;
 
	if (top < 22 || top > _screen.height - (height>>2)) return false;
 

	
 
	/* Make sure it is not obscured by any window. */
 
	FOR_ALL_WINDOWS(wz) {
 
		const Window *w = *wz;
 
		if (w->window_class == WC_MAIN_WINDOW) continue;
 

	
 
		if (left + width > w->left &&
 
				w->left + w->width > left &&
 
				top + height > w->top &&
 
				w->top + w->height > top) {
 
			return false;
 
		}
 
	}
 

	
 
	pos.x = left;
 
	pos.y = top;
 
	return true;
 
}
 

	
 
static Point GetAutoPlacePosition(int width, int height)
 
{
 
	Window* const *wz;
 
	Point pt;
 

	
 
	if (IsGoodAutoPlace1(0, 24, width, height, pt)) return pt;
 

	
 
	FOR_ALL_WINDOWS(wz) {
 
		const Window *w = *wz;
 
		if (w->window_class == WC_MAIN_WINDOW) continue;
 

	
 
		if (IsGoodAutoPlace1(w->left + w->width + 2, w->top, width, height, pt)) return pt;
0 comments (0 inline, 0 general)