pebble/devsite/source/tutorials/watchface-tutorial/part2.md
2025-02-24 18:58:29 -08:00

11 KiB

layout tutorial tutorial_part title description permalink generate_toc platform_choice
tutorials/tutorial watchface 2 Customizing Your Watchface A guide to personalizing your new Pebble watchface /tutorials/watchface-tutorial/part2/ true true

In the previous page of the tutorial, you learned how to create a new Pebble project, set it up as a basic watchface and use TickTimerService to display the current time. However, the design was pretty basic, so let's improve it with some customization!

In order to do this we will be using some new Pebble SDK concepts, including:

  • Resource management
  • Custom fonts (using GFont)
  • Images (using GBitmap and BitmapLayer)

These will allow us to completely change the look and feel of the watchface. We will provide some sample materials to use, but once you understand the process be sure to replace these with your own to truly make it your own! Once we're done, you should end up with a watchface looking like this:

{% screenshot_viewer %} { "image": "/images/getting-started/watchface-tutorial/2-final.png", "platforms": [ {"hw": "aplite", "wrapper": "steel-black"}, {"hw": "basalt", "wrapper": "time-red"}, {"hw": "chalk", "wrapper": "time-round-rosegold-14"} ] } {% endscreenshot_viewer %}

First Steps

To continue from the last part, you can either modify your existing Pebble project or create a new one, using the code from that project's main .c file as a starting template. For reference, that should look something like this.

^CP^ You can create a new CloudPebble project from this template by [clicking here]({{ site.links.cloudpebble }}ide/gist/9b9d50b990d742a3ae34).

The result of the first part should look something like this - a basic time display:

{% screenshot_viewer %} { "image": "/images/getting-started/watchface-tutorial/1-time.png", "platforms": [ {"hw": "aplite", "wrapper": "steel-black"}, {"hw": "basalt", "wrapper": "time-red"}, {"hw": "chalk", "wrapper": "time-round-rosegold-14"} ] } {% endscreenshot_viewer %}

Let's improve it!

Adding a Custom Font

^CP^ To add a custom font resource to use for the time display TextLayer, click 'Add New' on the left of the CloudPebble editor. Set the 'Resource Type' to 'TrueType font' and upload a font file. Choose an 'Identifier', which is the value we will use to refer to the font resource in the .c file. This must end with the desired font size, which must be small enough to show a wide time such as '23:50' in the TextLayer. If it does not fit, you can always return here to try another size. Click save and the font will be added to your project.

^LC^ App resources (fonts and images etc.) are managed in the package.json file in the project's root directory, as detailed in App Resources. All image files and fonts must reside in subfolders of the /resources folder of your project. Below is an example entry in the media array:

{% highlight {} %} "media": [ { "type": "font", "name": "FONT_PERFECT_DOS_48", "file": "fonts/perfect-dos-vga.ttf", "compatibility":"2.7" } ] {% endhighlight %}

^LC^ In the example above, we would place our perfect-dos-vga.ttf file in the /resources/fonts/ folder of our project.

A custom font file must be a TrueType font in the .ttf file format. [Here is an example font to use]({{ site.asset_path }}/fonts/getting-started/watchface-tutorial/perfect-dos-vga.ttf) (source).

Now we will substitute the system font used before (FONT_KEY_BITHAM_42_BOLD) for our newly imported one.

To do this, we will declare a GFont globally.

// Declare globally
static GFont s_time_font;

Next, we add the creation and substitution of the new GFont in the existing call to text_layer_set_font() in main_window_load(). Shown here is an example identifier used when uploading the font earlier, FONT_PERFECT_DOS_48, which is always pre-fixed with RESOURCE_ID_:

void main_window_load() {
  // ...
  // Create GFont
  s_time_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_PERFECT_DOS_48));

  // Apply to TextLayer
  text_layer_set_font(s_time_layer, s_time_font);
  // ...
}

And finally, safe destruction of the GFont in main_window_unload():

void main_window_unload() {
  // ...
  // Unload GFont
  fonts_unload_custom_font(s_time_font);
  // ...
}

^CP^ After re-compiling and re-installing (either by using the green 'Play' button to the top right of the CloudPebble editor, or by clicking 'Run Build' and 'Install and Run' on the 'Compilation' screen), the watchface should feature a much more interesting font.

^LC^ After re-compiling and re-installing with pebble build && pebble install, the watchface should feature a much more interesting font.

An example screenshot is shown below:

{% screenshot_viewer %} { "image": "/images/getting-started/watchface-tutorial/2-custom-font.png", "platforms": [ {"hw": "aplite", "wrapper": "steel-black"}, {"hw": "basalt", "wrapper": "time-red"}, {"hw": "chalk", "wrapper": "time-round-rosegold-14"} ] } {% endscreenshot_viewer %}

Adding a Bitmap

The Pebble SDK also allows you to use a 2-color (black and white) bitmap image in your watchface project. You can ensure that you meet this requirement by checking the export settings in your graphics package, or by purely using only white (#FFFFFF) and black (#000000) in the image's creation. Another alternative is to use a dithering tool such as HyperDither. This will be loaded from the watchface's resources into a GBitmap data structure before being displayed using a BitmapLayer element. These two behave in a similar fashion to GFont and TextLayer, so let's get started.

^CP^ The first step is the same as using a custom font; import the bitmap into CloudPebble as a resource by clicking 'Add New' next to 'Resources' on the left of the CloudPebble project screen. Ensure the 'Resource Type' is 'Bitmap image', choose an identifier for the resource and upload your file.

^LC^ You add a bitmap to the package.json file in the same way as a font, except the new media array object will have a type of bitmap. Below is an example:

{% highlight {} %} { "type": "bitmap", "name": "IMAGE_BACKGROUND", "file": "images/background.png" } {% endhighlight %}

As before, here is an example bitmap we have created for you to use, which looks like this:

[background]({{ site.asset_path }}/images/getting-started/watchface-tutorial/background.png)

Once this has been added to the project, return to your .c file and declare two more pointers, one each of GBitmap and BitmapLayer near the top of the file:

static BitmapLayer *s_background_layer;
static GBitmap *s_background_bitmap;

Now we will create both of these in main_window_load(). After both elements are created, we set the BitmapLayer to use our GBitmap and then add it as a child of the main Window as we did for the TextLayer.

However, is should be noted that the BitmapLayer must be added to the Window before the TextLayer. This will ensure that the text is drawn on top of the image. Otherwise, the text will be drawn behind the image and remain invisible to us. Here is that process in full, to be as clear as possible:

// Create GBitmap
s_background_bitmap = gbitmap_create_with_resource(RESOURCE_ID_IMAGE_BACKGROUND);

// Create BitmapLayer to display the GBitmap
s_background_layer = bitmap_layer_create(bounds);

// Set the bitmap onto the layer and add to the window
bitmap_layer_set_bitmap(s_background_layer, s_background_bitmap);
layer_add_child(window_layer, bitmap_layer_get_layer(s_background_layer));

As always, the final step should be to ensure we free up the memory consumed by these new elements in main_window_unload():

// Destroy GBitmap
gbitmap_destroy(s_background_bitmap);

// Destroy BitmapLayer
bitmap_layer_destroy(s_background_layer);

The final step is to set the background color of the main Window to match the background image. Do this in init():

window_set_background_color(s_main_window, GColorBlack);

With all this in place, the example background image should nicely frame the time and match the style of the new custom font. Of course, if you have used your own font and bitmap (highly recommended!) then your watchface will not look exactly like this.

{% screenshot_viewer %} { "image": "/images/getting-started/watchface-tutorial/2-final.png", "platforms": [ {"hw": "aplite", "wrapper": "steel-black"}, {"hw": "basalt", "wrapper": "time-red"}, {"hw": "chalk", "wrapper": "time-round-rosegold-14"} ] } {% endscreenshot_viewer %}

Conclusion

After adding a custom font and a background image, our new watchface now looks much nicer. If you want to go a bit further, try adding a new TextLayer in the same way as the time display one to show the current date (hint: look at the formatting options available for strftime()!)

As with last time, you can compare your own code to the example source code using the button below.

^CP^ [Edit in CloudPebble >{center,bg-lightblue,fg-white}]({{ site.links.cloudpebble }}ide/gist/d216d9e0b840ed296539)

^LC^ View Source Code >{center,bg-lightblue,fg-white}

What's Next?

The next section of the tutorial will introduce PebbleKit JS for adding web-based content to your watchface.

Go to Part 3 → >{wide,bg-dark-red,fg-white}