Allow text to scale to fit

Change-Id: Iacd4bb78f551b51d092ecde09521b5541e7dadcd
diff --git a/gui/button.cpp b/gui/button.cpp
index 18b5560..601a516 100644
--- a/gui/button.cpp
+++ b/gui/button.cpp
@@ -93,6 +93,23 @@
 		LoadPlacement(FindNode(node, "placement"), &x, &y, &w, &h, &TextPlacement);
 	}
 	SetRenderPos(x, y, w, h);
+	if (mButtonLabel) {
+		TextPlacement = (Placement)LoadAttrInt(FindNode(node, "placement"), "textplacement", TOP_LEFT);
+		if (TextPlacement != TEXT_ONLY_RIGHT) {
+			mButtonLabel->scaleWidth = 1;
+			mButtonLabel->SetMaxWidth(w);
+			mButtonLabel->SetPlacement(CENTER);
+			mTextX = ((mRenderW / 2) + mRenderX);
+			mTextY = mRenderY + (mRenderH / 2);
+			mButtonLabel->SetRenderPos(mTextX, mTextY);
+		} else {
+			mTextX = mRenderW + mRenderX + 5;
+			mRenderW += mTextW + 5;
+			mButtonLabel->GetCurrentBounds(mTextW, mTextH);
+			mTextY = mRenderY + (mRenderH / 2) - (mTextH / 2);
+			mButtonLabel->SetRenderPos(mTextX, mTextY);
+		}
+	}
 }
 
 GUIButton::~GUIButton()
@@ -125,15 +142,6 @@
 		mButtonLabel->GetCurrentBounds(w, h);
 		if (w != mTextW) {
 			mTextW = w;
-			if (TextPlacement == CENTER_X_ONLY) {
-				mTextX = ((mRenderW - mRenderX) / 2);
-			} else if (mTextW > mRenderW) { // As a special case, we'll allow large text which automatically moves it to the right.
-				mTextX = mRenderW + mRenderX + 5;
-				mRenderW += mTextW + 5;
-			} else {
-				mTextX = mRenderX + ((mRenderW - mTextW) / 2);
-			}
-			mButtonLabel->SetRenderPos(mTextX, mTextY);
 		}
 		ret = mButtonLabel->Render();
 		if (ret < 0)		return ret;
@@ -198,28 +206,19 @@
 	mTextW = 0;
 	mIconX = mRenderX + ((mRenderW - mIconW) / 2);
 	if (mButtonLabel)   mButtonLabel->GetCurrentBounds(mTextW, mTextH);
-	if (mTextW)
+	if (mTextW && TextPlacement == TEXT_ONLY_RIGHT)
 	{
-		if (TextPlacement == CENTER_X_ONLY) {
-			mTextX = ((mRenderW - mRenderX) / 2);
-		} else if (mTextW > mRenderW) { // As a special case, we'll allow large text which automatically moves it to the right.
-			mTextX = mRenderW + mRenderX + 5;
-			mRenderW += mTextW + 5;
-		} else {
-			mTextX = mRenderX + ((mRenderW - mTextW) / 2);
-		}
+		mRenderW += mTextW + 5;
 	}
 
 	if (mIconH == 0 || mTextH == 0 || mIconH + mTextH > mRenderH)
 	{
 		mIconY = mRenderY + (mRenderH / 2) - (mIconH / 2);
-		mTextY = mRenderY + (mRenderH / 2) - (mTextH / 2);
 	}
 	else
 	{
 		int divisor = mRenderH - (mIconH + mTextH);
 		mIconY = mRenderY + (divisor / 3);
-		mTextY = mRenderY + (divisor * 2 / 3) + mIconH;
 	}
 
 	if (mButtonLabel)   mButtonLabel->SetRenderPos(mTextX, mTextY);
diff --git a/gui/checkbox.cpp b/gui/checkbox.cpp
index 46a7708..8eb0f52 100644
--- a/gui/checkbox.cpp
+++ b/gui/checkbox.cpp
@@ -139,9 +139,11 @@
 	mRenderH = mCheckH;
 
 	mTextX = mRenderX + mCheckW + 5;
-	mTextY = mRenderY + ((mCheckH / 2) - (textH / 2));
+	mTextY = mRenderY + (mCheckH / 2);
 
 	mLabel->SetRenderPos(mTextX, mTextY, 0, 0);
+	mLabel->SetPlacement(TEXT_ONLY_RIGHT);
+	mLabel->SetMaxWidth(gr_fb_width() - mTextX);
 	SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
 	return 0;
 }
diff --git a/gui/console.cpp b/gui/console.cpp
index 1544d77..2d6414e 100644
--- a/gui/console.cpp
+++ b/gui/console.cpp
@@ -319,7 +319,7 @@
 
 	// render text
 	const char* text = rConsole[itemindex].c_str();
-	gr_textEx(mRenderX, yPos, text, mFont->GetResource());
+	gr_textEx_scaleW(mRenderX, yPos, text, mFont->GetResource(), mRenderW, TOP_LEFT, 0);
 }
 
 void GUIConsole::NotifySelect(size_t item_selected)
diff --git a/gui/devices/landscape/res/landscape.xml b/gui/devices/landscape/res/landscape.xml
index c75be3c..57406d9 100644
--- a/gui/devices/landscape/res/landscape.xml
+++ b/gui/devices/landscape/res/landscape.xml
@@ -990,7 +990,7 @@
 			</object>
 
 			<object type="button">
-				<placement x="%col3_x%" y="%row10_text_y%" />
+				<placement x="%col3_x%" y="%row10_text_y%" textplacement="6" />
 				<font resource="font" color="%text_color%" />
 				<condition var1="tw_mount_system_ro" op="=" var2="0" />
 				<text>Only mount system read-only</text>
@@ -999,7 +999,7 @@
 			</object>
 
 			<object type="button">
-				<placement x="%col3_x%" y="%row10_text_y%" />
+				<placement x="%col3_x%" y="%row10_text_y%" textplacement="6" />
 				<font resource="font" color="%text_color%" />
 				<condition var1="tw_mount_system_ro" op="!=" var2="0" />
 				<text>Only mount system read-only</text>
diff --git a/gui/devices/portrait/res/portrait.xml b/gui/devices/portrait/res/portrait.xml
index 969044c..db54e55 100644
--- a/gui/devices/portrait/res/portrait.xml
+++ b/gui/devices/portrait/res/portrait.xml
@@ -2125,7 +2125,7 @@
 			</object>
 
 			<object type="button">
-				<placement x="%col1_x%" y="%system_ro_y%" />
+				<placement x="%col1_x%" y="%system_ro_y%" textplacement="6" />
 				<font resource="font" color="%text_color%" />
 				<condition var1="tw_mount_system_ro" op="=" var2="0" />
 				<text>Only mount system read-only</text>
@@ -2134,7 +2134,7 @@
 			</object>
 
 			<object type="button">
-				<placement x="%col1_x%" y="%system_ro_y%" />
+				<placement x="%col1_x%" y="%system_ro_y%" textplacement="6" />
 				<font resource="font" color="%text_color%" />
 				<condition var1="tw_mount_system_ro" op="!=" var2="0" />
 				<text>Only mount system read-only</text>
diff --git a/gui/devices/watch/res/watch.xml b/gui/devices/watch/res/watch.xml
index 28198fb..00780d0 100644
--- a/gui/devices/watch/res/watch.xml
+++ b/gui/devices/watch/res/watch.xml
@@ -2133,7 +2133,7 @@
 			</object>
 
 			<object type="button">
-				<placement x="%col1_x%" y="%system_ro_y%" />
+				<placement x="%col1_x%" y="%system_ro_y%" textplacement="6" />
 				<font resource="font" color="%text_color%" />
 				<condition var1="tw_mount_system_ro" op="=" var2="0" />
 				<text>Only mount system read-only</text>
@@ -2142,7 +2142,7 @@
 			</object>
 
 			<object type="button">
-				<placement x="%col1_x%" y="%system_ro_y%" />
+				<placement x="%col1_x%" y="%system_ro_y%" textplacement="6" />
 				<font resource="font" color="%text_color%" />
 				<condition var1="tw_mount_system_ro" op="!=" var2="0" />
 				<text>Only mount system read-only</text>
diff --git a/gui/keyboard.cpp b/gui/keyboard.cpp
index f35a5d3..e55fb1b 100644
--- a/gui/keyboard.cpp
+++ b/gui/keyboard.cpp
@@ -326,7 +326,7 @@
 		int textH = labelFont->GetHeight();
 		int textX = keyX + (keyW - textW) / 2;
 		int textY = keyY + (keyH - textH) / 2;
-		gr_textEx(textX, textY, labelText.c_str(), fontResource);
+		gr_textEx_scaleW(textX, textY, labelText.c_str(), fontResource, keyW, TOP_LEFT, 0);
 	}
 
 	// longpress key label (only if font is defined)
@@ -339,7 +339,7 @@
 		int textW = gr_measureEx(text.c_str(), fontResource);
 		int textX = keyX + keyW - longpressOffsetX - textW;
 		int textY = keyY + longpressOffsetY;
-		gr_textEx(textX, textY, text.c_str(), fontResource);
+		gr_textEx_scaleW(textX, textY, text.c_str(), fontResource, keyW, TOP_LEFT, 0);
 	}
 }
 
diff --git a/gui/objects.hpp b/gui/objects.hpp
index 7028956..cf92024 100644
--- a/gui/objects.hpp
+++ b/gui/objects.hpp
@@ -34,6 +34,7 @@
 #include "resources.hpp"
 #include "pages.hpp"
 #include "../partitions.hpp"
+#include "placement.h"
 
 #ifndef TW_X_OFFSET
 #define TW_X_OFFSET 0
@@ -45,16 +46,6 @@
 class RenderObject
 {
 public:
-	enum Placement {
-		TOP_LEFT = 0,
-		TOP_RIGHT = 1,
-		BOTTOM_LEFT = 2,
-		BOTTOM_RIGHT = 3,
-		CENTER = 4,
-		CENTER_X_ONLY = 5,
-	};
-
-public:
 	RenderObject() { mRenderX = 0; mRenderY = 0; mRenderW = 0; mRenderH = 0; mPlacement = TOP_LEFT; }
 	virtual ~RenderObject() {}
 
@@ -207,6 +198,8 @@
 
 public:
 	bool isHighlighted;
+	bool scaleWidth;
+	unsigned maxWidth;
 
 protected:
 	std::string mText;
@@ -217,7 +210,6 @@
 	int mIsStatic;
 	int mVarChanged;
 	int mFontHeight;
-	unsigned maxWidth;
 	unsigned charSkip;
 };
 
@@ -1157,7 +1149,7 @@
 ImageResource* LoadAttrImage(xml_node<>* element, const char* attrname);
 AnimationResource* LoadAttrAnimation(xml_node<>* element, const char* attrname);
 
-bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w = NULL, int* h = NULL, RenderObject::Placement* placement = NULL);
+bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w = NULL, int* h = NULL, Placement* placement = NULL);
 
 #endif  // _OBJECTS_HEADER
 
diff --git a/gui/pages.cpp b/gui/pages.cpp
index 374a431..9bff289 100644
--- a/gui/pages.cpp
+++ b/gui/pages.cpp
@@ -229,7 +229,7 @@
 		return PageManager::GetResources()->FindAnimation(name);
 }
 
-bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, RenderObject::Placement* placement /* = NULL */)
+bool LoadPlacement(xml_node<>* node, int* x, int* y, int* w /* = NULL */, int* h /* = NULL */, Placement* placement /* = NULL */)
 {
 	if (!node)
 		return false;
@@ -247,7 +247,7 @@
 		*h = LoadAttrIntScaleY(node, "h");
 
 	if (placement && node->first_attribute("placement"))
-		*placement = (RenderObject::Placement) LoadAttrInt(node, "placement");
+		*placement = (Placement) LoadAttrInt(node, "placement");
 
 	return true;
 }
diff --git a/gui/placement.h b/gui/placement.h
new file mode 100644
index 0000000..02079e8
--- /dev/null
+++ b/gui/placement.h
@@ -0,0 +1,32 @@
+/*
+	Copyright 2015 bigbiff/Dees_Troy TeamWin
+	This file is part of TWRP/TeamWin Recovery Project.
+
+	TWRP is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	TWRP is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with TWRP.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __PLACEMENT_H
+#define __PLACEMENT_H
+
+enum Placement {
+	TOP_LEFT = 0,
+	TOP_RIGHT = 1,
+	BOTTOM_LEFT = 2,
+	BOTTOM_RIGHT = 3,
+	CENTER = 4,
+	CENTER_X_ONLY = 5,
+	TEXT_ONLY_RIGHT = 6,
+};
+
+#endif // __PLACEMENT_H
diff --git a/gui/scrolllist.cpp b/gui/scrolllist.cpp
index ec42fe6..7bd4598 100644
--- a/gui/scrolllist.cpp
+++ b/gui/scrolllist.cpp
@@ -266,7 +266,7 @@
 
 		// render the text
 		gr_color(mHeaderFontColor.red, mHeaderFontColor.green, mHeaderFontColor.blue, mHeaderFontColor.alpha);
-		gr_textEx(mRenderX + IconOffsetX + 5, yPos + (int)((mHeaderH - mFontHeight) / 2), mLastHeaderValue.c_str(), mFont->GetResource());
+		gr_textEx_scaleW(mRenderX + IconOffsetX + 5, yPos + (int)(mHeaderH / 2), mLastHeaderValue.c_str(), mFont->GetResource(), mRenderW, TEXT_ONLY_RIGHT, 0);
 
 		// Add the separator
 		gr_color(mHeaderSeparatorColor.red, mHeaderSeparatorColor.green, mHeaderSeparatorColor.blue, mHeaderSeparatorColor.alpha);
@@ -346,8 +346,8 @@
 
 	// render label text
 	int textX = mRenderX + maxIconWidth + 5;
-	int textY = yPos + (iconAndTextH - mFontHeight) / 2;
-	gr_textEx(textX, textY, text, mFont->GetResource());
+	int textY = yPos + (iconAndTextH / 2);
+	gr_textEx_scaleW(textX, textY, text, mFont->GetResource(), mRenderW, TEXT_ONLY_RIGHT, 0);
 }
 
 int GUIScrollList::Update(void)
diff --git a/gui/slider.cpp b/gui/slider.cpp
index a388447..6ee2024 100644
--- a/gui/slider.cpp
+++ b/gui/slider.cpp
@@ -80,6 +80,7 @@
 		sSliderLabel->GetCurrentBounds(w, h);
 		int sTextY = mRenderY + ((mRenderH - h) / 2);
 		sSliderLabel->SetRenderPos(sTextX, sTextY);
+		sSliderLabel->SetMaxWidth(mRenderW);
 	}
 	if (sTouch && sTouch->GetResource())
 	{
diff --git a/gui/slidervalue.cpp b/gui/slidervalue.cpp
index 3974c37..8a44a3c 100644
--- a/gui/slidervalue.cpp
+++ b/gui/slidervalue.cpp
@@ -307,15 +307,15 @@
 	if(mShowRange)
 	{
 		int rangeY = (mLineY - mLineH/2) - mFontHeight/2;
-		gr_textEx(mRenderX + mPadding/2, rangeY, mMinStr.c_str(), fontResource);
-		gr_textEx(mLineX + mLineW + mPadding/2, rangeY, mMaxStr.c_str(), fontResource);
+		gr_textEx_scaleW(mRenderX + mPadding/2, rangeY, mMinStr.c_str(), fontResource, mRenderW, TOP_LEFT, 0);
+		gr_textEx_scaleW(mLineX + mLineW + mPadding/2, rangeY, mMaxStr.c_str(), fontResource, mRenderW, TOP_LEFT, 0);
 	}
 
 	if(mValueStr && mShowCurr)
 	{
 		sprintf(mValueStr, "%d", mValue);
 		int textW = measureText(mValueStr);
-		gr_textEx(mRenderX + (mRenderW/2 - textW/2), mSliderY+mSliderH, mValueStr, fontResource);
+		gr_textEx_scaleW(mRenderX + (mRenderW/2 - textW/2), mSliderY+mSliderH, mValueStr, fontResource, mRenderW, TOP_LEFT, 0);
 	}
 
 	mRendered = true;
diff --git a/gui/text.cpp b/gui/text.cpp
index effb935..9898e28 100644
--- a/gui/text.cpp
+++ b/gui/text.cpp
@@ -34,7 +34,9 @@
 	mFontHeight = 0;
 	maxWidth = 0;
 	charSkip = 0;
+	scaleWidth = true;
 	isHighlighted = false;
+	mText = "";
 
 	if (!node)
 		return;
@@ -54,6 +56,23 @@
 	xml_node<>* child = FindNode(node, "text");
 	if (child)  mText = child->value();
 
+	child = FindNode(node, "noscaling");
+	if (child) {
+		scaleWidth = false;
+	} else {
+		if (mPlacement == TOP_LEFT || mPlacement == BOTTOM_LEFT) {
+			maxWidth = gr_fb_width() - mRenderX;
+		} else if (mPlacement == TOP_RIGHT || mPlacement == BOTTOM_RIGHT) {
+			maxWidth = mRenderX;
+		} else if (mPlacement == CENTER || mPlacement == CENTER_X_ONLY) {
+			if (mRenderX < gr_fb_width() / 2) {
+				maxWidth = mRenderX * 2;
+			} else {
+				maxWidth = (gr_fb_width() - mRenderX) * 2;
+			}
+		}
+	}
+
 	// Simple way to check for static state
 	mLastValue = gui_parse_text(mText);
 	if (mLastValue != mText)   mIsStatic = 0;
@@ -81,30 +100,13 @@
 	int x = mRenderX, y = mRenderY;
 	int width = gr_measureEx(displayValue.c_str(), fontResource);
 
-	if (mPlacement != TOP_LEFT && mPlacement != BOTTOM_LEFT)
-	{
-		if (mPlacement == CENTER || mPlacement == CENTER_X_ONLY)
-			x -= (width / 2);
-		else
-			x -= width;
-	}
-	if (mPlacement != TOP_LEFT && mPlacement != TOP_RIGHT)
-	{
-		if (mPlacement == CENTER)
-			y -= (mFontHeight / 2);
-		else if (mPlacement == BOTTOM_LEFT || mPlacement == BOTTOM_RIGHT)
-			y -= mFontHeight;
-	}
-
 	if (isHighlighted)
 		gr_color(mHighlightColor.red, mHighlightColor.green, mHighlightColor.blue, mHighlightColor.alpha);
 	else
 		gr_color(mColor.red, mColor.green, mColor.blue, mColor.alpha);
 
-	if (maxWidth)
-		gr_textExW(x, y, displayValue.c_str(), fontResource, maxWidth + x);
-	else
-		gr_textEx(x, y, displayValue.c_str(), fontResource);
+	gr_textEx_scaleW(mRenderX, mRenderY, displayValue.c_str(), fontResource, maxWidth, mPlacement, scaleWidth);
+
 	return 0;
 }
 
diff --git a/minuitwrp/graphics.c b/minuitwrp/graphics.c
index 5cc560e..fb86c14 100644
--- a/minuitwrp/graphics.c
+++ b/minuitwrp/graphics.c
@@ -33,6 +33,7 @@
 #include <pixelflinger/pixelflinger.h>
 
 #include "minui.h"
+#include "../gui/placement.h"
 
 #ifdef RECOVERY_BGRA
 #define PIXEL_FORMAT GGL_PIXEL_FORMAT_BGRA_8888
@@ -93,14 +94,14 @@
 #ifdef PRINT_SCREENINFO
 static void print_fb_var_screeninfo()
 {
-	printf("vi.xres: %d\n", vi.xres);
-	printf("vi.yres: %d\n", vi.yres);
-	printf("vi.xres_virtual: %d\n", vi.xres_virtual);
-	printf("vi.yres_virtual: %d\n", vi.yres_virtual);
-	printf("vi.xoffset: %d\n", vi.xoffset);
-	printf("vi.yoffset: %d\n", vi.yoffset);
-	printf("vi.bits_per_pixel: %d\n", vi.bits_per_pixel);
-	printf("vi.grayscale: %d\n", vi.grayscale);
+    printf("vi.xres: %d\n", vi.xres);
+    printf("vi.yres: %d\n", vi.yres);
+    printf("vi.xres_virtual: %d\n", vi.xres_virtual);
+    printf("vi.yres_virtual: %d\n", vi.yres_virtual);
+    printf("vi.xoffset: %d\n", vi.xoffset);
+    printf("vi.yoffset: %d\n", vi.yoffset);
+    printf("vi.bits_per_pixel: %d\n", vi.bits_per_pixel);
+    printf("vi.grayscale: %d\n", vi.grayscale);
 }
 #endif
 
@@ -221,20 +222,20 @@
         vi.transp.length  = 8;
     } else if (PIXEL_FORMAT == GGL_PIXEL_FORMAT_RGB_565) {
 #ifdef RECOVERY_RGB_565
-		fprintf(stderr, "Pixel format: RGB_565\n");
-		vi.blue.offset    = 0;
-		vi.green.offset   = 5;
-		vi.red.offset     = 11;
+        fprintf(stderr, "Pixel format: RGB_565\n");
+        vi.blue.offset    = 0;
+        vi.green.offset   = 5;
+        vi.red.offset     = 11;
 #else
         fprintf(stderr, "Pixel format: BGR_565\n");
-		vi.blue.offset    = 11;
-		vi.green.offset   = 5;
-		vi.red.offset     = 0;
+        vi.blue.offset    = 11;
+        vi.green.offset   = 5;
+        vi.red.offset     = 0;
 #endif
-		if (PIXEL_SIZE != 2)    fprintf(stderr, "E: Pixel Size mismatch!\n");
-		vi.blue.length    = 5;
-		vi.green.length   = 6;
-		vi.red.length     = 5;
+        if (PIXEL_SIZE != 2)    fprintf(stderr, "E: Pixel Size mismatch!\n");
+        vi.blue.length    = 5;
+        vi.green.length   = 6;
+        vi.red.length     = 5;
         vi.blue.msb_right = 0;
         vi.green.msb_right = 0;
         vi.red.msb_right = 0;
@@ -331,7 +332,7 @@
     }
 
 #ifdef PRINT_SCREENINFO
-	print_fb_var_screeninfo();
+    print_fb_var_screeninfo();
 #endif
 
     return fd;
@@ -433,6 +434,58 @@
     return gr_ttf_textExWH(gl, x, y, s, pFont, -1, -1);
 }
 
+int gr_textEx_scaleW(int x, int y, const char *s, void* pFont, int max_width, int placement, int scale)
+{
+    GGLContext *gl = gr_context;
+    void* vfont = pFont;
+    GRFont *font = (GRFont*) pFont;
+    unsigned off;
+    unsigned cwidth;
+    int y_scale = 0, measured_width, measured_height, ret, new_height;
+
+    if (!s || strlen(s) == 0 || !font)
+        return 0;
+
+    measured_height = gr_ttf_getMaxFontHeight(font);
+
+    if (scale) {
+        measured_width = gr_ttf_measureEx(s, vfont);
+        if (measured_width > max_width) {
+            // Adjust font size down until the text fits
+            void *new_font = gr_ttf_scaleFont(vfont, max_width, measured_width);
+            if (!new_font) {
+                printf("gr_textEx_scaleW new_font is NULL\n");
+                return 0;
+            }
+            measured_width = gr_ttf_measureEx(s, new_font);
+            // These next 2 lines adjust the y point based on the new font's height
+            new_height = gr_ttf_getMaxFontHeight(new_font);
+            y_scale = (measured_height - new_height) / 2;
+            vfont = new_font;
+        }
+    } else
+        measured_width = gr_ttf_measureEx(s, vfont);
+
+    int x_adj = measured_width;
+    if (measured_width > max_width)
+        x_adj = max_width;
+
+    if (placement != TOP_LEFT && placement != BOTTOM_LEFT && placement != TEXT_ONLY_RIGHT) {
+        if (placement == CENTER || placement == CENTER_X_ONLY)
+            x -= (x_adj / 2);
+        else
+            x -= x_adj;
+    }
+
+    if (placement != TOP_LEFT && placement != TOP_RIGHT) {
+        if (placement == CENTER || placement == TEXT_ONLY_RIGHT)
+            y -= (measured_height / 2);
+        else if (placement == BOTTOM_LEFT || placement == BOTTOM_RIGHT)
+            y -= measured_height;
+    }
+    return gr_ttf_textExWH(gl, x, y + y_scale, s, vfont, measured_width + x, -1);
+}
+
 int gr_textExW(int x, int y, const char *s, void* pFont, int max_width)
 {
     GGLContext *gl = gr_context;
diff --git a/minuitwrp/minui.h b/minuitwrp/minui.h
index 1744928..25a785a 100644
--- a/minuitwrp/minui.h
+++ b/minuitwrp/minui.h
@@ -17,6 +17,8 @@
 #ifndef _MINUI_H_
 #define _MINUI_H_
 
+#include "../gui/placement.h"
+
 typedef void* gr_surface;
 typedef unsigned short gr_pixel;
 
@@ -40,6 +42,7 @@
 gr_surface gr_render_circle(int radius, unsigned char r, unsigned char g, unsigned char b, unsigned char a);
 
 int gr_textEx(int x, int y, const char *s, void* font);
+int gr_textEx_scaleW(int x, int y, const char *s, void* pFont, int max_width, int placement, int scale);
 int gr_textExW(int x, int y, const char *s, void* font, int max_width);
 int gr_textExWH(int x, int y, const char *s, void* pFont, int max_width, int max_height);
 static inline int gr_text(int x, int y, const char *s)     { return gr_textEx(x, y, s, NULL); }
@@ -50,6 +53,7 @@
 int gr_getMaxFontHeight(void *font);
 
 void *gr_ttf_loadFont(const char *filename, int size, int dpi);
+void *gr_ttf_scaleFont(void *font, int max_width, int measured_width);
 void gr_ttf_freeFont(void *font);
 int gr_ttf_textExWH(void *context, int x, int y, const char *s, void *pFont, int max_width, int max_height);
 int gr_ttf_measureEx(const char *s, void *font);
diff --git a/minuitwrp/truetype.c b/minuitwrp/truetype.c
index 8f62ff2..d9ed019 100644
--- a/minuitwrp/truetype.c
+++ b/minuitwrp/truetype.c
@@ -265,6 +265,21 @@
     return res;
 }
 
+void *gr_ttf_scaleFont(void *font, int max_width, int measured_width)
+{
+    if (!font)
+        return NULL;
+
+    TrueTypeFont *f = font;
+    float scale_value = (float)(max_width) / (float)(measured_width);
+    int new_size = ((int)((float)f->size * scale_value)) - 1;
+    if (new_size < 1)
+        new_size = 1;
+    const char* file = f->key->path;
+    int dpi = f->dpi;
+    return gr_ttf_loadFont(file, new_size, dpi);
+}
+
 static bool gr_ttf_freeFontCache(void *key, void *value, void *context)
 {
     TrueTypeCacheEntry *e = value;