Maelstrom: Added support for resizable windows

https://github.com/libsdl-org/Maelstrom/commit/f2938dad3defb92b9ccad46492b4ca474f7ee1b0

From f2938dad3defb92b9ccad46492b4ca474f7ee1b0 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 15 Sep 2012 00:54:08 -0700
Subject: [PATCH] Added support for resizable windows

---
 screenlib/SDL_FrameBuf.cpp | 105 +++++++++++++++++++++++++++++--------
 screenlib/SDL_FrameBuf.h   |  48 +++++++++++------
 screenlib/UIManager.cpp    |  19 +++++++
 screenlib/UIPanel.h        |   1 +
 4 files changed, 134 insertions(+), 39 deletions(-)

diff --git a/screenlib/SDL_FrameBuf.cpp b/screenlib/SDL_FrameBuf.cpp
index 6e8d3bad..433e93cc 100644
--- a/screenlib/SDL_FrameBuf.cpp
+++ b/screenlib/SDL_FrameBuf.cpp
@@ -45,14 +45,14 @@ int
 FrameBuf:: Init(int width, int height, Uint32 window_flags, Uint32 render_flags,
 		SDL_Color *colors, SDL_Surface *icon)
 {
-	int w, h;
-
 #ifdef FAST_ITERATION
 	window_flags &= ~SDL_WINDOW_FULLSCREEN;
 #endif
-#ifdef __IPHONEOS__
-	window_flags |= SDL_WINDOW_FULLSCREEN;
-#endif
+//#ifdef __IPHONEOS__
+//	window_flags |= SDL_WINDOW_FULLSCREEN;
+//#endif
+	window_flags |= SDL_WINDOW_RESIZABLE;
+
 	window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, window_flags);
 	if (!window) {
 		SetError("Couldn't create %dx%d window: %s", 
@@ -66,6 +66,9 @@ FrameBuf:: Init(int width, int height, Uint32 window_flags, Uint32 render_flags,
 		return(-1);
 	}
 
+	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
+
+/*
 	texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, width, height);
 	if (!texture) {
 		SetError("Couldn't create target texture: %s", SDL_GetError());
@@ -76,8 +79,7 @@ FrameBuf:: Init(int width, int height, Uint32 window_flags, Uint32 render_flags,
 		SetError("Couldn't set render target: %s", SDL_GetError());
 		return(-1);
 	}
-
-	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
+*/
 
 	/* Set the icon, if any */
 	if ( icon ) {
@@ -85,16 +87,7 @@ FrameBuf:: Init(int width, int height, Uint32 window_flags, Uint32 render_flags,
 	}
 
 	/* Set the output area */
-	SDL_GetWindowSize(window, &w, &h);
-	output.w = w;
-	output.h = (height * w)/width;
-	output.x = (w - output.w) / 2;
-	output.y = (h - output.h) / 2;
-
-	clip.x = rect.x = 0;
-	clip.y = rect.y = 0;
-	clip.w = rect.w = width;
-	clip.h = rect.h = height;
+	UpdateWindowSize(width, height);
 
 	/* Copy the image colormap */
 	if ( colors ) {
@@ -127,6 +120,35 @@ FrameBuf:: SetPalette(SDL_Color *colors)
 	}
 }
 
+void
+FrameBuf::ProcessEvent(SDL_Event *event)
+{
+	switch (event->type) {
+	case SDL_WINDOWEVENT:
+		if (event->window.event == SDL_WINDOWEVENT_RESIZED) {
+			SDL_Window *window = SDL_GetWindowFromID(event->window.windowID);
+			int w, h;
+
+			SDL_GetWindowSize(window, &w, &h);
+			UpdateWindowSize(w, h);
+		}
+		break;
+	case SDL_MOUSEMOTION:
+		event->motion.x -= output.x;
+		event->motion.y -= output.y;
+		event->motion.x = (event->motion.x * rect.w) / output.w;
+		event->motion.y = (event->motion.y * rect.h) / output.h;
+		break;
+	case SDL_MOUSEBUTTONDOWN:
+	case SDL_MOUSEBUTTONUP:
+		event->button.x -= output.x;
+		event->button.y -= output.y;
+		event->motion.x = (event->motion.x * rect.w) / output.w;
+		event->motion.y = (event->motion.y * rect.h) / output.h;
+		break;
+	}
+}
+
 // This routine or something like it should probably go in SDL
 bool
 FrameBuf::ConvertTouchCoordinates(const SDL_TouchFingerEvent &finger, int *x, int *y)
@@ -199,17 +221,27 @@ FrameBuf:: QueueBlit(int dstx, int dsty, SDL_Texture *src,
 	SDL_RenderCopy(renderer, src, &srcrect, &dstrect);
 }
 
+void
+FrameBuf:: StretchBlit(const SDL_Rect *dstrect, SDL_Texture *src, const SDL_Rect *srcrect)
+{
+	SDL_RenderCopy(renderer, src, srcrect, dstrect);
+}
+
 void
 FrameBuf:: Update(void)
 {
 	/* Copy from our render texture to the screen and show it! */
-	SDL_SetRenderTarget(renderer, NULL);
-	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
-	SDL_RenderClear(renderer);
-	SDL_RenderCopy(renderer, texture, NULL, &output);
+	if (texture) {
+		SDL_SetRenderTarget(renderer, NULL);
+		SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+		SDL_RenderClear(renderer);
+		SDL_RenderCopy(renderer, texture, NULL, &output);
+	}
 	SDL_RenderPresent(renderer);
 
-	SDL_SetRenderTarget(renderer, texture);
+	if (texture) {
+		SDL_SetRenderTarget(renderer, texture);
+	}
 }
 
 void
@@ -339,3 +371,32 @@ FrameBuf:: FreeImage(SDL_Texture *image)
 {
 	SDL_DestroyTexture(image);
 }
+
+SDL_Texture *
+FrameBuf:: CreateRenderTarget(int w, int h)
+{
+	SDL_Texture *texture;
+
+	texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, w, h);
+	if (!texture) {
+		SetError("Couldn't create target texture: %s", SDL_GetError());
+		return NULL;
+	}
+	return texture;
+}
+
+int
+FrameBuf:: SetRenderTarget(SDL_Texture *texture)
+{
+	if (SDL_SetRenderTarget(renderer, texture) < 0) {
+		SetError("Couldn't set render target: %s", SDL_GetError());
+		return(-1);
+	}
+	return 0;
+}
+
+void
+FrameBuf:: FreeRenderTarget(SDL_Texture *texture)
+{
+	SDL_DestroyTexture(texture);
+}
diff --git a/screenlib/SDL_FrameBuf.h b/screenlib/SDL_FrameBuf.h
index a0a4d779..01fecb70 100644
--- a/screenlib/SDL_FrameBuf.h
+++ b/screenlib/SDL_FrameBuf.h
@@ -81,23 +81,8 @@ class FrameBuf : public ErrorBase {
 		}
 		return result;
 	}
-	void ProcessEvent(SDL_Event *event) {
-		switch (event->type) {
-			case SDL_MOUSEMOTION:
-				event->motion.x -= output.x;
-				event->motion.y -= output.y;
-				event->motion.x = (event->motion.x * rect.w) / output.w;
-				event->motion.y = (event->motion.y * rect.h) / output.h;
-				break;
-			case SDL_MOUSEBUTTONDOWN:
-			case SDL_MOUSEBUTTONUP:
-				event->button.x -= output.x;
-				event->button.y -= output.y;
-				event->motion.x = (event->motion.x * rect.w) / output.w;
-				event->motion.y = (event->motion.y * rect.h) / output.h;
-				break;
-		}
-	}
+	void ProcessEvent(SDL_Event *event);
+
 	bool ConvertTouchCoordinates(const SDL_TouchFingerEvent &finger, int *x, int *y);
 
 	void EnableTextInput();
@@ -130,6 +115,8 @@ class FrameBuf : public ErrorBase {
 		SDL_QueryTexture(src, NULL, NULL, &w, &h);
 		QueueBlit(x, y, src, 0, 0, w, h, do_clip);
 	}
+	void StretchBlit(const SDL_Rect *dstrect, SDL_Texture *src, const SDL_Rect *srcrect);
+
 	void Update(void);
 	void FadeOut(void) {
 		if (!faded) {
@@ -196,6 +183,12 @@ class FrameBuf : public ErrorBase {
 	}
 	void FreeImage(SDL_Texture *image);
 
+	/* Create a render target */
+	SDL_Texture *CreateRenderTarget(int w, int h);
+	int SetRenderTarget(SDL_Texture *texture);
+	void FreeRenderTarget(SDL_Texture *texture);
+	
+
 	/* Screen dump routines */
 	int ScreenDump(const char *prefix, int x, int y, int w, int h);
 
@@ -224,6 +217,27 @@ class FrameBuf : public ErrorBase {
 	SDL_Rect clip;
 	SDL_Rect output;
 
+	void UpdateWindowSize(int width, int height) {
+		int w, h;
+		SDL_Rect viewport;
+
+		SDL_GetWindowSize(window, &w, &h);
+		output.w = w;
+		output.h = (height * w)/width;
+		output.x = (w - output.w) / 2;
+		output.y = (h - output.h) / 2;
+
+		clip.x = rect.x = 0;
+		clip.y = rect.y = 0;
+		clip.w = rect.w = width;
+		clip.h = rect.h = height;
+
+		viewport.x = 0;
+		viewport.y = 0;
+		viewport.w = w;
+		viewport.h = h;
+		SDL_RenderSetViewport(renderer, &viewport);
+	}
 	void UpdateDrawColor(Uint32 color) {
 		Uint8 r, g, b;
 		r = (color >> 16) & 0xFF;
diff --git a/screenlib/UIManager.cpp b/screenlib/UIManager.cpp
index 84b98f44..bf9ec5cb 100644
--- a/screenlib/UIManager.cpp
+++ b/screenlib/UIManager.cpp
@@ -246,6 +246,25 @@ UIManager::Draw(bool fullUpdate)
 bool
 UIManager::HandleEvent(const SDL_Event &event)
 {
+	if (event.type == SDL_WINDOWEVENT &&
+	    event.window.event == SDL_WINDOWEVENT_RESIZED) {
+		SDL_Window *window = SDL_GetWindowFromID(event.window.windowID);
+		int w, h;
+		SDL_Rect clip;
+
+		SDL_GetWindowSize(window, &w, &h);
+
+		// Reset the clip rectangle
+		clip.x = 0;
+		clip.y = 0;
+		clip.w = w;
+		clip.h = h;
+		m_screen->ClipBlit(&clip);
+		
+		// Resize to match window size
+		SetSize(w, h);
+	}
+
 	for (unsigned i = m_visible.length(); i--; ) {
 		UIPanel *panel = m_visible[i];
 
diff --git a/screenlib/UIPanel.h b/screenlib/UIPanel.h
index ed48467a..2f603c6f 100644
--- a/screenlib/UIPanel.h
+++ b/screenlib/UIPanel.h
@@ -37,6 +37,7 @@ class UIPanelDelegate
 {
 public:
 	UIPanelDelegate(UIPanel *panel) { m_panel = panel; }
+	virtual ~UIPanelDelegate() { }
 
 	// This is called after the panel is loaded
 	virtual bool OnLoad() { return true; }