プチコンで遊ぼう! (はてなブログ版)

任天堂3DSのプチコンで遊ぼう! [twitter:@eida_s]

はてなダイアリーから移行しました。 はてなダイアリーのURLを開いても自動的にこちらにリダイレクトされますのでご了承ください。

Pebble Time 覚え書き2 最初のウォッチフェイス

C SDKでウォッチフェイスを作ってみる。
http://developer.getpebble.com/tutorials/watchface-tutorial/part1


1.CloudPebbleからログイン
https://cloudpebble.net/ide/
からCloudPebbleにログインする。

2.Projectの作成
PROJECTSから「CREATE」。
「CREATE NEW PROJECT」と出たら、
PROJECT NAME : プロジェクト名を入力する
PROJECT TYPE : Pebble C SDK
SDK VERSION : SDK 3
TEMPLATE : Empty project
を入力して「CREATE」。
要は、プロジェクト名だけ入力して「CREATE」。

3.Projectの設定
左にあるメニューの「SETTINGS」をクリック。
「APP KIND」という項目を探して、「Watchface」に変更する。

4.ソースの追加
左メニューの「SOURCE FILES」の横にある「ADD NEW」をクリック。
「CREATE NEW FILE」と出たら、
FILE TYPE : C file
FILENAME : ファイル名を入力する。ここでは「main.c」と入力
TARGET : App / Watchface
CREATE HEADER : チェックしない
を入力して「CREATE」。
要は、ファイル名だけ入力して「CREATE」。

5.ソースを入力 (空のウィンドウを表示)
main.cには以下の1行だけが最初から入力されている。

#include 

続いて以下をソースに入力する。

static Window *s_main_window;

static void main_window_load(Window *window) {

}

static void main_window_unload(Window *window) {

}

static void init() {
  // Create main Window element and assign to pointer
  s_main_window = window_create();

  // Set handlers to manage the elements inside the Window
  window_set_window_handlers(s_main_window, (WindowHandlers) {
    .load = main_window_load,
    .unload = main_window_unload
  });

  // Show the Window on the watch, with animated=true
  window_stack_push(s_main_window, true);
}

static void deinit() {
   // Destroy Window
  window_destroy(s_main_window);
}

int main(void) {
  init();
  app_event_loop();
  deinit();
}

Pebble SDKにおける標準的な記述方法はこのようにする。
init()でメモリの確保、deinit()でメモリの開放を行う処理を記述する。
また、main()の中にイベントループとしてapp_event_loop()の呼び出しを記述する。

画面を表示するにはWindowを作成しなければならないので、init()の中の2行目の処理でWindowを作成している。
その後で、Windowのloadとunload時のイベントで呼ばれる関数を関数ポインタとしてWindowHandlersに渡している。
window_stack_pushでWindowを表示している。

これで、何も表示しない、というか一面白色になるウィンドウを表示するウォッチフェイスが作成できた。

6.実行 (空のウィンドウを表示)
画面右上のプレイボタンみたいなボタン(ポイントすると「Save, build, install and run」と表示されるボタン。以後、実行ボタンと呼ぶ)をクリックすると、ビルドが始まり、自動的にエミュレータが起動してウォッチフェイスがインストールされ、ウォッチフェイスが起動するところまで行われる。
画面左上にエミュレータが表示され、白い画面が表示されたら成功。


7.ソースの修正 (何かテキストを表示させる)
先ほどのmain.cを再び開く。
文字を表示するにはTextLayerを使って描画する。
先ほど空だった、main_windows_loadの中に、TextLayerを作成して、テキストを描画する処理を追加する。
また、main_windows_unloadの中にTextLayerの開放処理を追加する。

static void main_window_load(Window *window) {
  // Create time TextLayer
  s_time_layer = text_layer_create(GRect(0, 55, 144, 50));
  text_layer_set_background_color(s_time_layer, GColorClear);
  text_layer_set_text_color(s_time_layer, GColorBlack);
  text_layer_set_text(s_time_layer, "00:00");

  // Improve the layout to be more like a watchface
  text_layer_set_font(s_time_layer, fonts_get_system_font(FONT_KEY_BITHAM_42_BOLD));
  text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);

  // Add it as a child layer to the Window's root layer
  layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_time_layer));
}

static void main_window_unload(Window *window) {
    // Destroy TextLayer
    text_layer_destroy(s_time_layer);
}

再び実行ボタンで実行。
画面左上のエミュレータに、「00:00」と表示されたら成功。


8.ソースの修正 (時計を表示させる)
再度main.cを開く。
時計を表示するには、イベントループの中で、一定時間ごとに処理が呼び出されるようにする必要がある。
このためには、TickTimerServiceに対して一定時間ごとに呼び出される処理を登録する。
TickTimerServiceから直接呼び出される処理は以下のようになる。

static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
  update_time();
}

また、init()の最後に、TickTimerServiceに1分ごとにtick_handlerを呼び出すように登録する処理を付け加える。

  // Register with TickTimerService
  tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);

そして、先ほどのtick_handlerから呼び出される、update_time(時計を描画する処理)
を追加する。

static void update_time() {
  // Get a tm structure
  time_t temp = time(NULL); 
  struct tm *tick_time = localtime(&temp);

  // Create a long-lived buffer
  static char buffer[] = "00:00";

  // Write the current hours and minutes into the buffer
  if(clock_is_24h_style() == true) {
    //Use 2h hour format
    strftime(buffer, sizeof("00:00"), "%H:%M", tick_time);
  } else {
    //Use 12 hour format
    strftime(buffer, sizeof("00:00"), "%I:%M", tick_time);
  }

  // Display this time on the TextLayer
  text_layer_set_text(s_time_layer, buffer);
}

また念のため、tick_handlerが最初に呼び出されるのがすぐとは限らないので、00:00を眺め続けることにならないように、main_window_unloadの最後にupdate_timeの呼び出しを追加しておく。

  // Make sure the time is displayed from the start
  update_time();

再び実行ボタンで実行。
画面左上のエミュレータに、現在の時刻が表示され、一分後に時計の表示が変われば成功。

最初の時計はこれで完成!