English |  Español |  Français |  Italiano |  Português |  Русский |  Shqip

Pebble Development

Building a Watchface

Unfortunately, the template application doesn’t do very much. But you can replace it with the example source code, example_src.c, from the SDK. This source code creates a basic watchface that displays the current time and automatically updates each second. We’ll use this to start understanding the basic principles. 

 

The full code is included below:

 

#include "pebble_os.h"

#include "pebble_app.h"

 

//! Generate your own UUID using `uuidgen` and replace it:

#define MY_UUID { 0x69, 0x5C, 0xE6, 0xFE, 0x5D, 0xC1, 0x43, 0x81, 0x85, 0x29, 0x9A, 0x82, 0xDB, 0x09, 0xA0, 0x69 }

PBL_APP_INFO(MY_UUID, "Digital Watch", "Initek", 1, 0, INVALID_RESOURCE, APP_INFO_WATCH_FACE);

 

Window s_window;

TextLayer s_text;

 

#define TIME_STR_BUFFER_BYTES 32

char s_time_str_buffer[TIME_STR_BUFFER_BYTES];

 

void handle_tick(AppContextRef ctx, PebbleTickEvent *event) {

  string_format_time(s_time_str_buffer, TIME_STR_BUFFER_BYTES, "%I:%M:%S %p", event->tick_time);

  text_layer_set_text(&s_text, s_time_str_buffer);

}

 

void handle_init(AppContextRef ctx) {

  (void)ctx;

 

  window_init(&s_window, "Digital Watch");

  window_stack_push(&s_window, true /* Animated */);

 

  text_layer_init(&s_text, s_window.layer.frame);

  strcpy(s_time_str_buffer, "");

  text_layer_set_text(&s_text, s_time_str_buffer);

  layer_add_child(&s_window.layer, &s_text.layer);

}

 

void pbl_main(void *params) {

  PebbleAppHandlers handlers = {

    .init_handler = &handle_init,

    .tick_info = {

      .tick_handler = &handle_tick,

      .tick_units = SECOND_UNIT

    }

  };

  app_event_loop(params, &handlers);

}

 

If we build and deploy it, then we get a really basic time display.

 

Let’s dig a little deeper and determine the basics of what is going on. We’ll start with the main function builds and runs the application.

 

void pbl_main(void *params) {

  PebbleAppHandlers handlers = {

    .init_handler = &handle_init,

    .tick_info = {

      .tick_handler = &handle_tick,

      .tick_units = SECOND_UNIT

    }

  };

  app_event_loop(params, &handlers);

}

 

The init_handler we’ve seen before and we’ll cover the details shortly. The tick_info block though is new. This configures the handler function that is executed each time there is clock tick. The tick handler is configurable from the perspective that you can define what handler operations are performed at different tick intervals. For example, we can call the tick handler every second, every minute, all the way up to year. 

 

Note that only one tick unit specification can be in place at a time, but we can make use of the interval specification to perform different updates at different times. The result can hugely affect the battery life of the app and particularly watchfaces. For example, in a display that includes the date and time, there is no need to redraw the date every second because it only changes every 24 hours.

 

At this level, what we’re defining is how frequently the handler is called. The handler itself must make the decision what to update and redraw. If your display only shows hours and minutes, there’s no need for the tick handler to update every second. 

 

Let’s look at what the tick handler does:

 

void handle_tick(AppContextRef ctx, PebbleTickEvent *event) {

  string_format_time(s_time_str_buffer, TIME_STR_BUFFER_BYTES, "%I:%M:%S %p", event->tick_time);

  text_layer_set_text(&s_text, s_time_str_buffer);

}

 

The handler has two statements, the first formats a character buffer with the time in the format in which we want to display it. The second updates the layer contents to contain the  the time string. 

 

Some important elements to extract from this; the function is supplied two arguments. The first is the application context, which defines information about the application. The second contains the event that triggered the handler; in this case, a clock tick. Within the clock tick is the tick_time element that contains the current time in seconds since the epoch, and it’s used as the source for setting the time. 

 

The text layer was created by the initialization handler which creates the basic screen structure. Let’s look at that next. 

 

void handle_init(AppContextRef ctx) {

  (void)ctx;

 

  window_init(&s_window, "Digital Watch");

  window_stack_push(&s_window, true /* Animated */);

 

  text_layer_init(&s_text, s_window.layer.frame);

  strcpy(s_time_str_buffer, "");

  text_layer_set_text(&s_text, s_time_str_buffer);

  layer_add_child(&s_window.layer, &s_text.layer);

}

 

The initialization function does three things:

 

  • Creates a window and adds it to the stack of windows for this application
  • Creates a text layer and populates it with an empty string
  • Adds the text layer as a child of the main window

 

This creates the basic UI of the entire application - a single window with a single layer with some text in it. 

 

We can represent the entire application with a simple diagram:

 

 

And to describe that basic execution layout: 

 

  1. pebble_main configures handler functions that are called during initialization and for each clock tick at an accuracy of a second. 

 

  1. During initialization, a window is created and within the window a text layer to contain the time. 

 

  1. At each clock tick, we update the text layer with the current time. 

 

The watchface that is created in this example is incredibly simplistic, but, the basics should also be easy to understand. Let’s see what we can do to improve that layout.

There has been error in communication with Booktype server. Not sure right now where is the problem.

You should refresh this page.