Pebble SDK 2.0 Tutorial #3: Images and Fonts

Required Reading

Pebble SDK 2.0 Tutorial #1: Your First Watchapp

Pebble SDK 2.0 Tutorial #2: Telling the Time

Introduction

So now you’ve learned how to create a watchface and spice it up a bit with a well placed InverterLayer. But it’s still pretty dull. A much better way to improve it is to use your own images and fonts. That’s what this section will focus on.

In a Pebble watch app or watchface, images and fonts are referred to in the app’s appinfo.json file, which is managed automatically for you by CloudPebble, and so will not be covered in great detail right now. Of much more importance to you now is that in the C code file, images are stored in GBitmap structures and fonts in GFont structures. Just like all the Layer types, they are created and allocated memory dynamically, with the function names syntactically very similar, so you will hopefully find yourself looking them up in the API Documentation a lot less.

Making a Better First Impression

You have probably noticed that all your favorite watchapps have their own icon in the Pebble system menu, and so the first thing we’re going to do is add one to our tutorial face we’ve been building up over the last couple of sections. Once again, create a new project over at CloudPebble and add a main.c file containing the finished code from the last tutorial section.

Next, select ‘Add new’ from the ‘Resources’ menu on the left, leave the type as PNG and browse for a file of 8-bit 2-colour PNG format with a size of 24×28 pixels. Below is one you can use for now:

menu_iconGive it an identifier, such as ‘MENU_ICON’ and click ‘Save’. Next, go to ‘Settings’ and choose the file you just added from the ‘Menu image’ dropdown menu.  Then click ‘Save changes’.

Making the Watchface More Appealing

Let’s add some more artistic direction to our watch face. At the moment, it probably looks like this:

pebble-screenshot_2013-12-22_13-59-31Not very appealing. Let’s use images to add detail to the InverterLayer. Below are two samples I created that we can use to do just that:

future past As with the menu icon, the first step is to add both images as Resources in CloudPebble and give them appropriate identifiers, such as FUTURE and PAST respectively. Next, go back to the C source file and declare two global pointers of type GBitmap and two of type BitmapLayer, like so:

GBitmap *future_bitmap, *past_bitmap;
BitmapLayer *future_layer, *past_layer;

The GBitmaps will contain the image data, and the BitmapLayers will present the images to the user as a Layer. So, in window_load(), add the appropriate function calls to create these elements. Here is how it is done. Try and understand what each line does, using your previous knowledge of the TextLayer and InverterLayer:

//Load bitmaps into GBitmap structures
//The ID you chose when uploading is prefixed with 'RESOURCE_ID_'
future_bitmap = gbitmap_create_with_resource(RESOURCE_ID_FUTURE);
past_bitmap = gbitmap_create_with_resource(RESOURCE_ID_PAST);

//Create BitmapLayers to show GBitmaps and add to Window
//Sample images are 144 x 50 pixels
future_layer = bitmap_layer_create(GRect(0, 0, 144, 50));
bitmap_layer_set_bitmap(future_layer, future_bitmap);
layer_add_child(window_get_root_layer(window), bitmap_layer_get_layer(future_layer));

past_layer = bitmap_layer_create(GRect(0, 112, 144, 50));
bitmap_layer_set_bitmap(past_layer, past_bitmap);
layer_add_child(window_get_root_layer(window), bitmap_layer_get_layer(past_layer));

Once again, we need to add the de-init code to free up the memory again:

//Destroy GBitmaps
gbitmap_destroy(future_bitmap);
gbitmap_destroy(past_bitmap);

//Destroy BitmapLayers
bitmap_layer_destroy(future_layer);
bitmap_layer_destroy(past_layer);

Are you beginning to spot patterns in how the API function calls are named? This way once you’ve worked with a new layer it is easier to guess correctly what to call for newer elements and reducing your dependence on the API documentation. Once all this has been done, your watchface should look like this:
pebble-screenshot_2013-12-22_14-43-19

Custom Fonts

Another good way to add your own influence to your watchface is to use a custom font. The procedure for doing so it almost identical to that for images, so let’s do it now.

First, again, add the font as a Resource in CloudPebble. This time set the format to ‘TrueType font’. The font you choose will need to the a ‘.ttf’ font file. Here’s a sample for you to use now. Once you have browsed for the file, give it an identifier such as IMAGINE_42. The number after the name tells the SDK what font size you want. The rest of the settings can be left alone for now, so click ‘Save’ and go back to the C file.

The process for using the font in the watchface is almost the same as that for the images. First, load the resource into a ResHandle (Handle on the Resource, so to speak) structure BEFORE the TextLayer is created (We will be using it for the time display itself):

//Load font
ResHandle font_handle = resource_get_handle(RESOURCE_ID_IMAGINE_42);

Now, modify the call to text_layer_set_font() to use our custom font and a slight layout modification to the text position by modifying the GRect to have a width of 144 pixels, like so:

text_layer = text_layer_create(GRect(0, 53, 144, 168));

...

text_layer_set_font(text_layer, fonts_load_custom_font(font_handle));

After compilation, the watchface should finally look like so:
pebble-screenshot_2013-12-22_15-00-53

Much better!

Conclusion

So there you have using custom images and fonts. If you want, add some more or change the existing ones (being careful with the dimensions in the code!) to see for yourself what small modifications can do to the look an feel.

Next time: Animations: Tweens and Timers.

The full source code the the end result of this part of the tutorial can be found on GitHub.

Advertisements
11 comments
  1. Bryn said:

    How would you go about doing the icons in the SDK, not CloudPebble?

    • bonsitm said:

      Hi Bryn,

      To set the app icon in the Linux SDK, you declare the resource in the ‘media’ array in appinfo.json. After this simply add the field and value of ‘”menuIcon”: true’.

      Here is an example JSON with an app image resource set.

      Good luck!

  2. Kris said:

    Thanks for the great tutorials! I’m having trouble with PNGs with transparency. I can’t even get the SDK sample project (with the panda face) to work with transparent PNGs. Do you have any pointers?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: