Up front notice: I am neither the designer nor the developer of the window chrome in Windows Vista.
I have been using Windows Vista Beta 2 as my primary operating system since it was released. My overall impression so far: it is really, really tight. Sure, there are still some warts. Sure, I have to relearn a number of things that at one point I could do without thinking. But overall, it really feels good.
Of course, my purpose in posting is not to shower praise on the product. Give it a try yourself and form your opinions. Rather, I wanted to take one small aspect of the design and dissect it from my own, very personal, point of view. It illustrates to me very clearly how important the little details are in implementing a great design.
One of the most clearly (bad pun, I know) visible aspects of the UI design is that the windows are partially transparent. Not quite transparent, really - they actually distort the image behind them (using pixel shaders). However, as soon as you maximize a window, the transparency goes away. Why?
Windows Vista Beta 2 Glass Windows: Maximized (top) and Normal (bottom)
To understand this decision, it is important to think about the story that the designers are trying to tell with the glass windows. What is their purpose? Is it just to look cool? In this case, looking cool is certainly part of the story, but I suspect the real intention here is to keep the window chrome out of the way. This story is completely consistent with the behavior we are seeing. When in normal mode, the window chrome (which we add on to windows) gives you access to key window management functionality, but other than that it just just extra stuff that blocks your view of other items on your desktop. By making it get out of the way somewhat, it blocks those items less. However, if it were completely transparent or undistorted, then you could see the items behind it a little bit too clearly, thus raising their importance so they begin to get in the way. It is a delicate balance - reduce the heaviness of the chrome, but don't reduce it so much that other items start to become distractions. Whether they have it perfectly balanced is in the eye of the beholder, and in fact the control panel will let you tweak that balance if they didn't nail it to your liking.
When you maximize a window, however, you are communicating a very different intent. You no longer need to have the ability to maneuver windows around with these light weight frames. How do we know that? Because you can't maneuver windows around while they are maximized! If the window chrome started showing what was behind that window, it would add new things to get in the way, with no real purpose for showing these things as a means of getting out of the way. Reducing the brightness and removing the transparency when maximized is a clever way of following the same principal - the window chrome should be secondary to the content of that window. It should stay out of the way in the most appropriate way, based on the user's intent. Clever.
Clever, but not perfect.
If it were perfect, you see, nobody would ever ask that question, because it would be inherently obvious what was happening and why.
How could it better communicate the rationale? My first thought - what if it animated? As it is right now (which, admittedly, could be due to some very early WDDM drivers), the window chrome literally snaps from glass to opaque. What if this were animated? Then, we could see what was happening and increase our likelihood of understanding correctly. If the alpha faded away and the luminance decreased smoothly, then it might do a better job of sending the message, "Hey, I see that there is no more reason for me to show you what is behind me, so I'll go ahead and get out of the way now."
When I think of animation, this is the type of communication that I think it is best used for. Yes, with Windows Presentation Foundation, you can make buttons bounce arbitrarily around the screen with almost no code. But why would you ever want that? However, when you use animation to communicate rather than just look cool, then you have hit the sweet spot.
What else do I find imperfect? This is a bit more subtle, and deals with my personal response to the user interface.
The human mind is optimized for pattern matching. We are consistently anthropomorphising, consistently seeing metaphors. When I maneuver glass windows around my desktop, I don't just see the pixels. I personally see (feel?) an application drawing surface resting on a very high quality glass frame in 3-dimensional space. I really like the feel of the material that my brain is inferring. It feels expensive. When I maximize a window, it literally feels to me as if it has changed material. The texture is different. Rather than this expensive glass, now it feels more like plastic. Even more, I begin to see the pixels at the top of the frame as pixels instead of as natural shading and highlighting, causing me to stop suspending my disbelief in the metaphor my mind has created.
My logical mind tells me that the "texture" my brain is seeing is caused by the pixel shaders, and not by anything that is explicitly rendered on the chrome. As soon as you take the pixel shaders away (for a sound design reason, mind you), how can you maintain that sense of texture? I don't know. What I do know, however, is that I like the "feel" of that chrome enough that it changes my behavior. Rather than maximize my windows, which leaves me with the cheap plasticy frame with pixels drawn on it, I leave my windows restored and just stretch them to fill my desktop. I like the feel of the material that much.
What can I learn from this? First, you can see just how important it is to tell a story and communicate. The window chrome in Windows Vista Beta 2 tells such a story. Animation can help tell that story, and it should be used when it has the power to communicate. Most importantly, I learned never to underestimate how emotions can influence the experience of your user interface. It is more than about pixels. It is about manipulating an experience and leveraging the pattern seeking tendencies of the human brain to make people feel good about software (or, at a minimum, avoid making them feel bad). Logic does not always trump emotions.
I have been somewhat distracted lately, so it has been a while since I posted. I have been knee deep in a number of projects I am working on with one of our customers, and last week, I was volunteering as a Marshal at the U.S. Open Golf Tournament.
Working as a marshal provided me with a whole new perspective on professional golf. Standing directly behind the pros on the tees really gives you a better feel for the decisions that each of them makes. I was specifically working at the 18th hole, which is a particularly challenging dog-leg left. I began to observe how the percentage of pros who were hitting a 3-wood off the tees instead of a driver changed as the winds changed. (And no, I have no idea why Phil hit a driver on 18, especially after he played it safe by hitting a 4-iron on 15.)
Approach to the green at the 9th Hole of Winged Foot's West Course
What really struck me was coming face to face with the fact that this is their job.
And not everybody seemed to be enjoying it.
Now, this may not be exactly fair, given that golf is one of these sports that seems designed to be intentionally frustrating. (It certainly can be for me.) But it was interesting to watch the interactions. One of the caddies who walked past me exhaled deeply, saying "whew, it's almost over." Here is a human being who is tired and ready to get off of work. How often do you normally think of that? A couple of players were joking around with some of the spectators who happened to be calling out to them with particularly heavy New York accents. (References to The Sopranos were thrown around.) They were having a great time, and they were helping the spectators have a great time.
However, some of the pros never cracked a smile. They would take the path between the green of one hole and the tee of the next that minimized the interaction they would have to have with fans. It almost seemed as if this were nothing more than an exercise in rote gross motor control that happened to have a potentially gigantic reward.
As somebody who makes a living exercising creativity, decision making, and fine motor control (well, I do have to tell my fingers what to do on this little keyboard of mine), it really struck me just how sad I would be if I couldn't exercise what talents I happen to have without closing myself off to others, the joy of what I was doing, and sheer, raw exhuberance.
I want to savor every moment of what I am doing.
So, this little experience not only gave me a great view of a golf tournament (inside the rope access does give you a better view, at the cost of not being able to move around freely if what happens to be in front of you is not what you are most interested in), it also gave me a voyeuristic glimpse into another career where technical expertise is what is valued. From this experience, I have renewed my resolve to really savor the experience of working, and not just the rewards of working.
If you have the right job, then it's just too fun not to enjoy it.
By the way, if you were watching the tournament, the 7th hole is where I shot my first birdie ever. (And one of the only ones - let's face it, gross motor control isn't really my forte.)
Last time around, I suggested, "Let's see if I can talk about something other than rendering text next time around..." It looks like the answer to that one is no.
Windows Vista has reached Beta 2, and we are already beginning to see documentation around lighting up your applications on Windows Vista. One of the ways to make your application feel more like Vista is to use fonts consistent with the UI: Segoe UI. The fonts section of the Windows Vista User Experience Guideliness discusses using Segoe UI - the system font. This documentation specifies, "From code, you can determine the system font properties (including its size) using the GetThemeFont API function."
Unfortunately, this is all of the direction that it provides. Anybody who has played around with the GetThemeFont API realizes that this is easier said than done. There are a respectably large number of permutations of classes, parts, and states, and anybody who is working in managed code will need to rifle through include files from the Platform SDK to locate all of the values to pass in. Once you have that working, you will then discover that the vast majority of permutations do not contain a font value at all, and the documentation is pretty much silent on the topic of which values to use to improve your chances of success, making this all the more challenging to the developer.
You can avoid a significant amount of p/invoke code by using the Visual Styles API - the VisualStylesRenderer class provides a GetFont method that wraps the unmanaged GetThemeFont API for you, but you are still left with the problem of locating a permutation of class, part, and state that return a Font at all, let alone the one you are hoping to use!
Personally, I find it much easier to use the GetThemeSysFont API to retrieve the system font. With this API, you specify whether you want to retreive the caption, small caption, menu, status, message box, or icon title font. Personally, I use the message box font, given that this font is also designed to display readable, sentence-formatted text. Lets' take a look at how this looks:
GetThemeSysFont on Windows XP SP-2
GetThemeSysFont on Windows Vista Beta 2
The source code to construct this simple example follows:
namespace GetThemeSysFont { using System; using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; using System.Windows.Forms.VisualStyles; public partial class Form1 : Form { #region p/invoke declarations [DllImport("uxtheme.dll", ExactSpelling = true, CharSet = CharSet.Unicode)] private static extern IntPtr OpenThemeData(IntPtr hWnd, String classList); [DllImport("uxtheme", ExactSpelling = true, CharSet = CharSet.Unicode)] private extern static Int32 GetThemeSysFont(IntPtr hTheme, int iFontId, out LOGFONT plf); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct LOGFONT { public int lfHeight; public int lfWidth; public int lfEscapement; public int lfOrientation; public int lfWeight; public byte lfItalic; public byte lfUnderline; public byte lfStrikeOut; public byte lfCharSet; public byte lfOutPrecision; public byte lfClipPrecision; public byte lfQuality; public byte lfPitchAndFamily; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string lfFaceSize; } private const int TMT_CAPTIONFONT = 801; private const int TMT_SMALLCAPTIONFONT = 802; private const int TMT_MENUFONT = 803; private const int TMT_STATUSFONT = 804; private const int TMT_MSGBOXFONT = 805; private const int TMT_ICONTITLEFONT = 806; #endregion public Form1() { InitializeComponent(); Font themeFont = messageBoxFont(); platformLabel.Font = themeFont; platformLabel.Text = Environment.OSVersion.VersionString; themeFontLabel.Font = themeFont; themeFontLabel.Text = "Message Box Font: " + themeFont.Name + " " + themeFont.SizeInPoints + "pt"; } private Font messageBoxFont() { // You can avoid p/invoke altogether in managed code // using the following: // return SystemFonts.MessageBoxFont; LOGFONT pFont; IntPtr hTheme = OpenThemeData(this.Handle, "WINDOW"); GetThemeSysFont(hTheme, TMT_MSGBOXFONT, out pFont); return Font.FromLogFont(pFont); } } }
This approach will work well in both managed code and unmanaged code. Unfortunately, I am not aware of a wrapper in the managed Visual Styles APIs for GetThemeSysFont, so I went the p/invoke route.
Are there other alternatives to getting the system font? Yes there are! (If you read the commented out code, you will even see one - we'll get to that one in a bit.)
Well, we are getting the message box font. If you poke around the NONCLIENTMETRICS structure you can retrieve from a call to SystemParametersInfo, you will notice that there is a lfMessageFont LOGFONT that returns the message box font. This works in both managed and unmanaged code, and has the distinct advantage of not taking a dependency on uxtheme.dll - which you will only find on Windows XP and above.
What about nice shortcuts in the managed world? The SystemFonts class, by its very name, suggests that it will return the correct system font. Unfortunately, if you go with the most obvious choice, the DefaultFont property, you will be handed a font that is very clearly not Segoe UI. What has happened here? Well, internally, the DefaultFont property has a very strong tendency to return the hard-coded value of Tahoma (depending on your locale). Otherwise, you get the outcome GetStockObject(DEFAULT_GUI_FONT). Wait a minute, the DEFAULT_GUI_FONT? The one Raymond Chen describes as, "DEFAULT_GUI_FONT has an even less illustrious history. It was created during Windows 95 development in the hopes of becoming the new default GUI font, but by July 1994, Windows itself stopped using it in favor of the various fonts returned by the SystemParametersInfo function. Its existence is now vestigial."? Yes, that's the one.
OK, so DefaultFont isn't a particularly good choice. That's unfortunate, because it just "feels" like it should be the right choice.
However, the MessageBoxFont property does, indeed, wrap the SystemParametersInfo function with an argument of NONCLIENTMETRICS, giving you a straightforward way to go after this font without having to use p/invoke.
So, in the end, MessageBoxFont is probably the easiest option to go after Segoe UI on Vista using managed code, while providing acceptable results on existing platforms.