Developing for Windows Mobile – Animation Basics

This post is a follow on from my most recent efforts creating some screens for a Windows Mobile application. I had decided to write a simple graphics library to help me do some nice transition effects. So over the last two nights I ported (actually rewrote) my original WinForms Transition demo to Windows Compact Framework.

So far I have support only for polygons, but that includes hit testing, transforms (rotate, translate, scale), animation (floats, points, colours, brushes) and easing functions (currently sine in/out and elastic out).

Hopefully I’ll post more about this (with source code) soon – but here is a quick demo video that I captured using Expression 3’s new screen capture utility (very neat!).

Windows Mobile Animations_Thumb

So far I’ve been really happy with the performance. Will be interesting to see how much it degrades once I start adding gradients, transparency and more complex shapes. [Note that the video doesn’t really reflect the performance too well.]

Developing for Windows Mobile – Getting Started

Now I have my new Windows Mobile 6.1 device I’ve decided to delve once more into the mysterious realm of developing for mobile devices. My previous forays have both been very lightweight. The most recent was simply displaying bus timetable information within a ListView control. Despite its simplicity its actually something I find very useful on my daily commute – rather than digging around in my bag for the paper version and then tuning in to the times and stops that I’m interested in.

Here’s a screenshot of my original Bus Timetable applet (its just too trivial to be awarded the title “application”):

BusTimetable - PocketPC 2003 SE

Now here’s a screenshot of the same application running on my new HTC device:

2009 07 06_21 15 12_0015_111g

Hmm.. some things scaled and some didn’t But overall when compared to the other default applications (particularly those written by HTC) it looks pretty lame.

So, I decided to get to work and create a user interface that:

  1. Scales well across the more common Windows Mobile devices resolutions (at least 240×320, 480×640 and 480×800).
  2. Fits with the “look and feel” of the pre-installed HTC applications.
  3. Works with touch only – this type of application needs to work using just my thumb since common scenarios for its use are when I’m walking through a crowd and carrying a bag.

With the help of the UIFramework from MSDN I managed to get some screens that I was pretty happy with. The icons and selection had gradient fills and the icons were superimposed on their corresponding “frames” with a transparent background.

2009 07 06_21 27 31_0016_111g  2009 07 06_21 28 35_0018_111g 

However, I soon found that things weren’t quite a rosy as I was hoping. To start with the UIFramework library sample seems to be a “work in progress”. That is to say it has a lot of bugs or parts that simply don’t work – its obviously intended as a starting reference for someone intending to owner draw their own controls/graphic elements.

Also, I originally created each ButtonBar as a user control. As with WinForms this meant that when it came to scrolling the buttons it looked terrible. Really slow – and each button is its own Window hence there is no capability of double-buffering. Man – I have been so spoiled by WPF – I had long forgotten all this pain! This trick then seemed to be to ditch using controls and just render the entire UI on a single user control. That way the main user control can double buffer all the rendering and there is only one render pass. The downside of course is that you then have to take care of everything – drawing all your own controls, hit testing, anchoring, dpi scaling etc.

Well – I’m not sure where I’m going with all this. But I did consider porting my WinForms Transitions code to the Windows CF. Even this was a no-go though – because although it contains plenty of base classes and helper methods for transforming and hit testing objects it relies heavily on using GraphicsContainer to do the actual transforms. These aren’t supported by the Compact Framework. So, I started from scratch, building a simple graphics library that will let me scale, rotate and translate graphic primitives. So far I have a spinning/zoomable rectangle – guess you gotta start somewhere.

MobileTransitions

Comment Spam Philosophy

Recently I’ve been getting quite a bit of comment spam on this blog. Most of it is inane gibberish, a witless praise or a text fragment ripped from the post itself. However, some of it is actually quite entertaining…



Although Google does not care much about links inside comments, Google cares about links INSIDE the posts. Get people to notice you, and they will eventually write about you and your site. Links inside posts are the best quality backlinks you can get. To sum it all up, always write great comments if you are going to write them, and you will be rewarded sooner or later.


Hmm – spam that tells me comment links are not really worth anything.



I admit, I have not been on this webpage in a long time… however it was another joy to see It is such an important topic and ignored by so many, even professionals. I thank you to help making people more aware of possible issues.
Great stuff as usual….


Well what can I say – its good to have you back.



The scoop neck and cap sleeves are cute, the gathers at the waist creates a uniformly flattering silhouette, and the pattern of the dye compliments beautifully the design of the dress!..


Why – thank you so much, I designed it myself :-p



Find effective graphics and photos: It’s always better to use too few than too many graphics. One great graphic is so much better than four weak ones. Sometimes they are not even necessary. When you do use graphics and photos, make sure they help illustrate your point, rather than just inserting them to take up space.


Err… OK – use a few good graphics… when necessary… but not more than four… and make them relevant not as padding. Even graphic designers are spamming!?



nice post! It helps me a lot to optimize my site… now my newly published site are get index by search engine especially Google…


Your new site “are get index” by Google – fancy Mr Spammer caring about that?



I would like to thank you for the efforts you have made in writing this article. I am hoping the same best work from you in the future as well. In fact your creative writing abilities has inspired me to start my own wordpress blog now. Really the blogging is spreading its wings rapidly. Your write up is a fine example of it


Oh wonderful, my half-assed blog posts are inspiring the spammers to start their own blogs. I’m soooo proud

NHibernate – a Quality ORM?

[This is a flame. If you are an NHibernate fan, please stop reading now, you’ll only upset yourself otherwise.]

Like many others I subscribe to the codebetter.com RSS feed. One of the members feels that its their personal responsibility to enlighten subscribers with endless NDepend analysis results for various frameworks. I almost always skip those posts.

However, this latest post regarding the NHibernate 2.1 release I found most amusing.

I’ve been subjected to NHibernate. I don’t enjoy the experience. Some of the pain that I’ve felt begins to make sense. 58,000 lines of spaghetti code to do some pretty simple ORM mapping – woot! {snigger}

Windows Mobile SDK disables Sierra 880U NextG Wireless Card

On my 50 minute bus trip home I often get out my laptop – whether its to finishing checking-in my days work via VPN, getting a headstart with projects that I’m working on at home, of even just catching up with blogs/mail etc.

Tonight I fired up the laptop, inserted my Telstra Wireless NextG card and… nothing. Just the message “Card not detected”. Tried both other USB ports no luck. Opened up device manager and there it was – exclamation marks against all the Network Adapters and Ports associated with my Sierra Aircard 880U. Not good!

I tried all the usual, time honoured, general purposes fix measures:

  • Reboot the machine
  • Disable and re-enable the devices
  • Un-install the devices and do a hardware scan to re-install them

No luck. When I got home I removed the drivers and tried to re-install from the original installation disk that came with the device. The installer failed right after selecting the modem device. So I re-installed the driver manually from the CD. The installation worked but still the device wasn’t detected.

Time to backtrack – it was working flawlessly last week. Once I’d got to this point the culprit became obvious. I had installed Windows Mobile 6.0 and 6.5 Developer Tools on the weekend so I could start doing development for my new phone on my laptop. It made a quirky kind of sense that this installation could have somehow installed some virtual drivers that were interfering with the real HDSPA modem.

Sure enough. After uninstalling Windows Mobile 6.0 Developer Tools and Windows Mobile 6.5 Emulators then re-inserting the modem it worked immediately. Great! But how do I get to have a working NextG Wireless Card and developer for a Windows Mobile device!? Is this just some quirky hardware issue on my laptop/install?

Continuous Tile Panel

A couple of weeks ago someone suggested to me an idea for a particular type of layout panel. The idea was to be able to display a fixed set of tiles which are “wrapped” horizontally. So as you scroll horizontally the tiles will move off one edge of the panel and eventually re-appear on the other side. Think of how we commonly see the earth projected onto a rectangle – scrolling left or right to bring the particular geography into the centre of the screen.

I jumped into this without giving too much thought about how I would want to interact with the panel from an API perspective. For that reason its probably I’ve taken altogether the wrong approach but I thought I would post it up here anyway, ‘cause its unlikely I’ll take it any further than this proof of concept.

Usage

Define some XAML like so:

<panels:TilePanel x:Name="tilePanel" Height="170"
Rows="3" Background="LightYellow" ClipToBounds="True"
XOffset="{Binding ElementName=xOffsetSlider,Path=Value,Mode=OneWay}"
YOffset="{Binding ElementName=yOffsetSlider,Path=Value,Mode=OneWay}"
Scale="{Binding ElementName=scaleSlider,Path=Value,Mode=OneWay}">
<panels:TilePanel.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="32pt"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="TextAlignment" Value="Center"/>
<Setter Property="Background" Value="LightBlue"/>
</Style>
</panels:TilePanel.Resources>
<TextBlock>A</TextBlock>
<TextBlock>B</TextBlock>
<TextBlock>C</TextBlock>
<TextBlock>D</TextBlock>
<TextBlock>E</TextBlock>
<TextBlock>F</TextBlock>
<TextBlock>G</TextBlock>
<TextBlock>H</TextBlock>
<TextBlock>I</TextBlock>
<TextBlock>J</TextBlock>
<TextBlock>K</TextBlock>
<TextBlock>L</TextBlock>
<TextBlock>M</TextBlock>
<TextBlock>N</TextBlock>
<TextBlock>O</TextBlock>
<TextBlock>P</TextBlock>
<TextBlock>Q</TextBlock>
<TextBlock>R</TextBlock>
<TextBlock>S</TextBlock>
<TextBlock>T</TextBlock>
<TextBlock>U</TextBlock>
<TextBlock>V</TextBlock>
<TextBlock>W</TextBlock>
<TextBlock>X</TextBlock>
<TextBlock>Y</TextBlock>
<TextBlock>Z</TextBlock>
<TextBlock>1</TextBlock>
<TextBlock>2</TextBlock>
<TextBlock>3</TextBlock>
<TextBlock>4</TextBlock>
<TextBlock>5</TextBlock>
<TextBlock>6</TextBlock>
<TextBlock>7</TextBlock>
<TextBlock>8</TextBlock>
<TextBlock>9</TextBlock>
<TextBlock>0</TextBlock>
</panels:TilePanel>

This generates the following layout where each of the items is laid out in three rows.

Continuous Tile Panel - Letters at Start

Items that are beyond the right edge are actually wrapped back to the left hand side (by subtracting the total width of all columns). So that when we supply a horizontal offset we get the desired effect.

Continuous Tile Panel - Letters Shifted

Note that in the example each column width is automatically calculated based on the widest element. Likewise row heights are calculated based on the tallest elements. Although this allows for different widths/heights per column/row its works well when all items are the same width and height.

One example usage of this control would be as an ItemsPanel for an ItemsControl that displays tiled images that form a single scene. It so happens that ICE generates these types of tiles (at various zoom levels) for publishing its panoramas.

<ItemsControl ItemsSource="{Binding TileSet}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="LightGray">
<Grid>
<Image Source="{Binding ImagePath}" Stretch="Uniform" Height="Auto"/>
                    <TextBlock Margin="4" TextAlignment="Center" FontSize="6pt" Foreground="White" Opacity="0.5" 
VerticalAlignment="Center" HorizontalAlignment
="Center"> <TextBlock.Text> <MultiBinding StringFormat="{}{0},{1}" > <Binding Path="ColumnIndex"/> <Binding Path="RowIndex"/> </MultiBinding> </TextBlock.Text> </TextBlock> </Grid> </Border> </DataTemplate> </ItemsControl.ItemTemplate> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <panels:TilePanel Margin="10" Background="LightYellow" ClipToBounds="True" Rows="{Binding TileSet.RowCount}" XOffset="{Binding ElementName=xOffsetSlider,Path=Value,Mode=OneWay}" YOffset="{Binding ElementName=yOffsetSlider,Path=Value,Mode=OneWay}" Scale="{Binding ElementName=scaleSlider,Path=Value,Mode=OneWay}"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl>

Continuous Tile Panel - ICE

 

Code

To load the ICE images into a collection of “Tiles” I wrote the following.

    public static class TileLoader
{
public static TileSet LoadFromFolder( string path, int zoomLevel )
{
var result = new TileSet(path, zoomLevel);
if ( !Directory.Exists( path ) )
throw new ArgumentException( "The specified tile folder does not exist.", "path" );
if ( zoomLevel < 0 )
throw new ArgumentException( "The zoom level must be >= 0.", "zoomLevel" );
DirectoryInfo tileLevelFolder;
try
{
var rootFolder = new DirectoryInfo( path );
var tileFolder = new DirectoryInfo( Path.Combine( path, "tiles" ) );
tileLevelFolder = new DirectoryInfo( Path.Combine( tileFolder.FullName, "l_" + zoomLevel ) );
}
catch ( System.IO.IOException ex )
{
throw new ArgumentException( 
string.Format( "The tile set specified by the path {0} is corrupt.", path ), "path", ex ); } var column = 0;
// Order the directories by numerical ascending, e.g. c_3 before c_21 foreach ( var columnFolder in tileLevelFolder.GetDirectories( "c_*" )
.OrderBy( d => int.Parse( d.Name.Substring( 2 ) ) ) ) { var row = 0; foreach ( var imageFile in columnFolder.GetFiles( "tile_*.wdp" )
.OrderBy( i => int.Parse( i.Name.Substring( 5, i.Name.IndexOf( '.' ) - 5 ) ) ) ) { var tile = new Tile() { ColumnIndex = column, RowIndex = row, ImagePath = imageFile.FullName }; result.Add( tile ); row++; if ( result.RowCount < row ) result.RowCount = row; } column++; } return result; } } [DebuggerDisplay("Column: {ColumnIndex}, Row: {RowIndex}, {ImagePath}")] public class
Tile { public string ImagePath { get; set; } public int ColumnIndex { get; set; } public int RowIndex { get; set; } } public class TileSet : List<Tile> { public TileSet( string path, int zoomLevel ) { Path = path; ZoomLevel = zoomLevel; } public string Path { get; protected set; } public int ZoomLevel { get; protected set; } public int RowCount { get; set; } }

The panel’s arrange override code is as follows:

protected override Size ArrangeOverride(Size finalSize)
{
int row = 0;
int column = 0;
double fullWidth = _columnWidths.Sum();
double fullHeight = _rowHeights.Sum();
int maxColumns = (int) Math.Ceiling( (double) finalSize.Width / (double) _maxChildWidth);
double x = -( XOffset * _maxChildWidth );
double y = - YOffset;
foreach (UIElement child in Children)
{
x = x % fullWidth;
if (x >= Math.Min(_maxChildWidth * maxColumns, fullWidth - _maxChildWidth + 1))
x -= fullWidth;
else if (x < - _maxChildWidth)
x += fullWidth;
if ( x > -_maxChildWidth && x <= _maxChildWidth * maxColumns &&
y > -_maxChildHeight && y <= fullHeight )
{
child.Arrange( 
new Rect( new Point( x * Scale, y * Scale ),
new Size( child.DesiredSize.Width * Scale, child.DesiredSize.Height * Scale ) ) ); child.Visibility = Visibility.Visible; }
else { child.Visibility = Visibility.Hidden; child.Arrange( new Rect( new Point( 0, 0 ), new Size( child.DesiredSize.Width * Scale, child.DesiredSize.Height * Scale ) ) ); } y += _rowHeights[ row ]; row = ( row + 1 ) % Rows; if ( row == 0 ) { x += _columnWidths[ column ]; //column * _childWidth ; y = -YOffset ; column++; } } //RenderTransform = new ScaleTransform(Scale, Scale, 0.0, YOffset); return finalSize; }

This is far from complete – sample project can be found here. [It’s a VS2010 project but should be easy enough to re-assemble for VS2008.]

 

Screen Resolution

There has been plenty of talk over the last handful of years about how we should be writing applications that are device resolution independent. For example, designing screen elements in terms of real world measurements like millimetres (or for the metrically challenged – inches). There is no point designing a button that is designed to be touched by a large thumb at a resolution of 100 pixels by 40 pixels when its deployed to a 300 ppi (pixels per inch) device.

In the past I’ve read a few articles that have claimed getting to the 300 ppi mark would mean that screens would become as readable as paper (ignoring light emitting vs. light absorbing for a moment). Well, I don’t know about that but I’ve finally got myself a (near) 300 ppi device – and it is an awesome screen. Shown here below at half pixel resolution and still larger than life size on most (96 ppi) desktop monitors (click for full image).

HTC Home Page

The latest HTC range comes with a WVGA resolution screen (480 x 800 pixels) crammed into a screen that is only 42 x 70 mm. By my calculations that is 290 ppi compared to the blurry old iPhone 3Gs at 163 ppi. Now all we need is say a 24” widescreen LCD monitor at this resolution – hmm… that’s around 5902 x 3688 pixels!