HelloWorld

[Also posted on CitrixBlogger. The code is easier to read there.]
Not long ago, a member of the team thought it would be a good idea to show the simplest program possible using the Mobile SDK for Windows Apps.  This was an excellent idea since “Hello World” is commonly used to introduce developers to new concepts.  The history of “Hello World” comes from the early 1970s with the C language and has prevailed even though things have changed so much since then.

The first step is to provide you with a really basic version of “Hello World” using WinForms.  Get the code from here.  It is a really small download at around 25K.  The download is a full Visual Studio 2010 project and even includes the bin directory with the HelloWorld.exe binary.  The binary is not signed so if you do not trust it you can build your own copy.

The code that drives this app is short so I will include in full here.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace HelloWorld
{
    /// <summary>
    /// The HelloWorld form demonstrates how to display "Hello World" with the appropriate font based on the size of the client area.
    /// Later, this will be transformed to support the Mobile SDK for Windows Apps.
    /// </summary>
    public partial class HelloWorld : Form
    {
        /// <summary>
        /// Main constructor for HelloWorld Form
        /// </summary>
        public HelloWorld()
        {
            // initialize the designer standard components
            InitializeComponent();

            // make sure that this window is maximized
            WindowState = FormWindowState.Maximized;
        }

        /// <summary>
        /// Called when the form is first loaded.  Resize the HelloWorldLabel to fit the new form size
        /// </summary>
        /// <param name="sender">Ignored</param>
        /// <param name="e">Ignored</param>
        private void HelloWorld_Load(object sender, EventArgs e)
        {
            ResizeHelloWorld();
        }

        /// <summary>
        /// Called when the form is resized.  Resize the HelloWorldLabel to fit the new form size
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void HelloWorld_Resize(object sender, EventArgs e)
        {
            ResizeHelloWorld();
        }

        /// <summary>
        /// Resize the Hello World to fill the client area
        /// </summary>
        void ResizeHelloWorld()
        {
            // change the font to match the size of the client area
            HelloWorldLabel.Font = GetBestFontFit(ClientSize, HelloWorldLabel.Font, HelloWorldLabel.Text, ClientSize.Height, 8f); ;

            // center the label
            CenterHelloWorld();
        }

        /// <summary>
        /// Center the HelloWorldLabel in the client area of HelloWorld form
        /// </summary>
        void CenterHelloWorld()
        {
            HelloWorldLabel.Location = new Point((ClientSize.Width / 2) - (HelloWorldLabel.Width / 2), (ClientSize.Height / 2) - (HelloWorldLabel.Height / 2));
        }

        /// <summary>
        /// Determine the best font match for the size/text.  The result should be between the maximum and minimum height.
        /// The size is the area to fill.  The new font is based on the old font which is passed in.
        /// </summary>
        /// Font
        public static Font GetBestFontFit(Size size, Font currFont, String text, float fontMax, float fontMin)
        {
            float fontPixels = fontMax;
            float minfontPixels = fontMin;

            // find the corresponding font size for the textbox size
            Font font = currFont;

            // make sure that the text is not null or empty before attempting to fit it in the area.
            // if it is null or empty, the current font is used since it does not matter.
            if (!String.IsNullOrEmpty(text))
            {
                Size textsize;

                font = new Font(currFont.FontFamily, fontPixels, currFont.Style, GraphicsUnit.Pixel);

                textsize = TextRenderer.MeasureText(text, font);

                // Check to see if the font fits in the area and if not, find a smaller one
                while ((((textsize.Height) &gt; size.Height) || ((textsize.Width) &gt; size.Width)) &amp;&amp; (fontPixels &gt; minfontPixels))
                {
                    // try to speed up the process of finding the right font size by detecting how much it is too big by
                    if (textsize.Height &gt; size.Height)
                    {
                        // reduce the fontPixels based on how far off the font size is
                        fontPixels -= (textsize.Height - size.Height);
                    }
                    else if (textsize.Width &gt; size.Width)
                    {
                        int charPixelWidth = textsize.Width / text.Length;
                        int targetPixelWidth = size.Width / text.Length;

                        // if the characters are too wide, reduce the fontPixels by how different the result is from the desired width
                        if (charPixelWidth &gt; targetPixelWidth)
                        {
                            fontPixels -= (charPixelWidth - targetPixelWidth);
                        }
                        else
                        {
                            fontPixels -= 1.0F;
                        }
                    }
                    else
                    {
                        fontPixels -= 1.0F;
                    }

                    // drop the old one since it did not work
                    font.Dispose();

                    // get a new font based on the smaller font pixels size
                    font = new Font(font.FontFamily, fontPixels, font.Style, GraphicsUnit.Pixel);

                    // recalculate the size based on the new font
                    textsize = TextRenderer.MeasureText(text, font);
                }
            }

            // when all done, return the font to use
            return (font);
        }

    }
}

The most complicated part is figuring out the proper font to use to fill the client area. This code was modified from the code that is being used for UserInfo from the previous posts. The idea is that it loops over attempts to find the correct font starting from the biggest size to the minimum size.

The end result is a program that always shows “Hello World” in its biggest font possible to fit in the client area. If you change the size of the window, the text will adjust to fill it again. This is a good introduction to the concept of having text be re-sized to fit a specified rectangle. The effect is quite interesting if you re-size it constantly and see how fast the text adjusts. It almost appears to be an animation.

The next step will be to introduce the Mobile SDK for Windows Apps. This is mostly for the sake of matching the size of the display and the orientation.