PebbleTime 開発 - HelloWorld のコード説明
前回 は、CloudPebble を使って HelloWorld を作成し、エミュレータで動作確認するところまで見ました。
今回は、コードを説明していきます。
基本なので良く理解してください。
ソースコード
これが hello_world.c の全コードです。
コードの説明です。
include <pebble.h>
#include <pebble.h>
Pebble SDK を使用する場合は、pebble.h をインクルードしてください。
それにより API や型が定義されます。
なお、自分で作成したヘッダは #include "foo.h" でインクルードできます。
main 関数
まずは main 関数ですね。
これがないと始まりません。
int main(void) { handle_init(); app_event_loop(); handle_deinit(); }
この中で handle_init と handle_deinit はこのファイルで定義した関数ですね。
それぞれ、Watchface 起動時に必要な資源の確保と、終了時の資源開放処理です。
では app_event_loop は何でしょう?
app_event_loop 関数
これはいわゆるイベントループ関数です(関数名そのままですが)。 GUI のプログラムを作ったことがある人はおなじみですね。
Pebble のアプリは、Watchface にしろ Watchapp*1 にしろ様々なイベントを受け取って動いています。 ボタンの入力、加速度センサー、タイマーやスマートフォンからの通信など。 それらのイベントはいつ発生するか分からないので*2、 全てのイベントを待ち続ける必要があります。 また、イベントが発生したらすぐに処理する必要もあります。 ボタンが押されてから 1 分後に画面が変わるのでは、その Watchface は使えません。
それらの取りまとめは大変なので、SDK が代わりにやってくれます。 それがこの関数です。
なお、この関数は必ず実行する必要があります。
Watchface を作るときは、main 関数はこれと同じにすると良いでしょう。
http://developer.getpebble.com/docs/c/Foundation/App/#app_event_loop
この関数にかぎらず、SDK に関することは全てオンラインマニュアルに載っているので、一読すると良いです。全て英語ですが…。
handle_init 関数
では、main から呼ばれている handle_init を見て行きましょう。
この関数では以下の処理を行っています。
- window の生成
- text_layer の生成
- text_layer に表示する文字や、フォントの情報を設定
- text_layer を window 内の root_layer の子レイヤーに登録
- window を Window Stack に登録
- ログを表示
レイヤーモデル
Watchface の画面は、以下の様なレイヤーモデルで作られています。

2015-07-05 追記
上記の図は、text_layer の背景が透明となっていましたが、実際には白色でした。
修正した図に差し替えました。
まず、土台なる window があり、そこには必ず root_layer が乗っています。
これだけだと何も表示しないので、今回はさらにその上に text_layer が乗せて文字を表示しています。
Watchface を作るときは、複数のレイヤーを重ねて一つの画面を作ります。
レイヤーとは文字や画像を表示するためのシートのようなもので、レイヤー同士を重ねることができます。
2015-07-05 修正
レイヤーは透明なので、重ねてもその下のレイヤーが見えます。もちろん色を塗って下のレイヤーを見せないようにすることもできます。
レイヤーは、背景を透明にして下のレイヤーを見せることもできますし、色を塗って見せないようにすることもできます。
root_layer と text_layer の背景はデフォルトで白色です。
Window
では、window を作成するコードを見てみましょう。
handle_init 関数の先頭で作成しています。
Window *window; void handle_init(void) { window = window_create(); .... window_stack_push(window, true); }
window は Window 型のポインタです。
window_create 関数により作成します。
その後、window_stack_push しています。これは何でしょう。
ウィンドウ・スタックモデル
先ほど、レイヤーモデルを紹介しました。
土台となる window があるのでした。
その window は、それ自体も重ねることができます。

レイヤーは、重ねることで画面を作るのでした。Window は何のために重ねるのでしょう。
Window は、別の画面を表示したいときに重ねます。 たとえば設定画面を表示するときなどです。 非透明のレイヤーを重ねても別の画面を表示できるのですが、Window を重ねるとボタンの制御を作りやすいという利点があります。 今回は Window はひとつですし、Watchface なのでボタンは使わないですが、今後の記事でそれらも取り上げていきます。
Window を重ねるときは window_stack_push を使います。第1引数には重ねたい Window を、第2引数には重ねた時にアニメーションさせるか否かを true か false で設定します。
true を設定した場合は、Window が右から左へ滑り込むように表示されます*3。
TextLayer
次は text_layer を生成するコードを見てみましょう。text_layer は文字を表示するためのレイヤーです。
TextLayer *text_layer; void handle_init(void) { .... text_layer = text_layer_create(GRect(0, 0, 144, 154)); .... }
text_layer は TextLayer 型のポインタです。
text_layer_create 関数により作成します。
第1引数の GRect(0, 0, 144, 154) はレイヤーの位置と大きさです。
この例だと「位置 0,0 に大きさ 144x154 のレイヤーを作成する」となります。
TextLayer に表示する文字列の設定
その後、text_layer を第1引数に取る3つの関数を実行しています。
void handle_init(void) { .... text_layer_set_text(text_layer, "Hi, I'm a Pebble!"); text_layer_set_font(text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD)); text_layer_set_text_alignment(text_layer, GTextAlignmentCenter); .... }
これらは表示する文字列に関する設定です。
| 関数名 | 説明 |
|---|---|
| text_layer_set_text | 表示する文字列を設定します。 今回は "Hi, I'm a Pebble!" と表示します。 |
| text_layer_set_font | 表示するフォントを設定します。 今回は GOTHIC フォントを28ポイントの大きさで太字で表示します。 |
| text_layer_set_text_alignment | 表示する位置を設定します。 今回は中央に寄せて表示します。 |
TextLayer を root_layer に重ねる
TextLayer は作っただけでは表示できません。root_layer に重ねることにより、初めて表示されます。
void handle_init(void) { .... layer_add_child(window_get_root_layer(window), text_layer_get_layer(text_layer)); .... }
レイヤーを重ねるには layer_add_child を使います。
第1引数に土台となるレイヤーを、第2引数に重ねたいレイヤーを設定します。
今回は root_layer に text_layer を重ねたいのですが何やら複雑なコードです。
何をやっているのでしょう。
これは、Layer を取得しているのです。
| 引数 | コード | 説明 |
|---|---|---|
| 第1引数 | window_get_root_layer(window) | window から root_layer(Layer型)を取得する |
| 第2引数 | text_layer_get_layer(text_layer) | text_layer から Layer を取得する |
ここで layer_add_child の定義を見てみましょう。
void layer_add_child ( Layer * parent, Layer * child )
http://developer.getpebble.com/docs/c/User_Interface/Layers/#layer_add_child
どちらの引数も Layer 型を要求しています。
text_layer は TextLayer 型なのでそのままでは渡せません。
そこで text_layer_get_layer 関数を用いて text_layer に含まれる Layer 型のオブジェクトを取得して渡しています。
ログ表示
handle_init 関数の最後では、ログを表示しています。
void handle_init(void) { .... APP_LOG(APP_LOG_LEVEL_DEBUG, "Just pushed a window!"); }
APP_LOG はログを表示するための関数(実際にはマクロ関数)で、第1引数にログレベルを、第2引数にログ文字列を設定します。
ログレベルというのは、ログの緊急度です*4。以下の5つが定義されています。
| ログレベル | 説明 |
|---|---|
| APP_LOG_LEVEL_ERROR | エラーが発生したことを通知する。 |
| APP_LOG_LEVEL_WARNING | 何らかの警告を通知する。 |
| APP_LOG_LEVEL_INFO | 一般的な情報を通知する。 |
| APP_LOG_LEVEL_DEBUG | デバッグ用のログを表示する。 |
| APP_LOG_LEVEL_DEBUG_VERBOSE | デバッグログの詳細を表示する。 |
レベルは定義されていますが、今のところレベルでフィルタしたりできないので、あまり気にすることはないです。 作成する Watchface 内で意味が統一されていれば良いでしょう。
ちなみに、今回の場合は以下のように表示されます。
[DEBUG] hello_world.c:23: Just pushed a window!
APP_LOG の詳細に関しては、以下のオンラインマニュアルを参照してください。
http://developer.getpebble.com/docs/c/Foundation/Logging/#APP_LOG
handle_deinit 関数
handle_init の説明はちょっと長かったですね。
handle_deinit は短いのでご安心を。
やっているのはこれだけです。
text_layerの削除windowの削除
使っている API はオンラインマニュアルを見て理解してください。
終わり。
まとめ
今回のまとめです。
#include <pebble.h>は必須main関数は毎回この形- ウィンドウ・スタックモデルとレイヤーモデルがある
windowはroot_layerというレイヤーを持っている- レイヤーは
root_layerに重ねないと表示されない - ログにはレベルがある(が今のところ気にしなくてよい)
- XxxLayer 型の API 名には規則性がある
- APIリファレンスはここ
あとがき
Watchface の画面の構造がイメージできたでしょうか。 まだ説明が足りないところもありますが、今後の記事で説明していきます。
次回は、このコードを修正して時間を表示してみたいと思います。
PebbleTime は、公式サイトでプレオーダーを受付中です。 2015-07-03 現在で $199.99 です。
Amazon.co.jp に並行輸入品が出てますね。 ただ、正直高いです。 公式サイトで買うことをおすすめします。
![Pebble Time スマートウォッチ 腕時計 (レッド) [並行輸入品] Pebble Time スマートウォッチ 腕時計 (レッド) [並行輸入品]](http://ecx.images-amazon.com/images/I/41IymqHG-RL._SL160_.jpg)
Pebble Time スマートウォッチ 腕時計 (レッド) [並行輸入品]
- 出版社/メーカー: Pebble
- メディア: 時計
- この商品を含むブログを見る
こちらは古い白黒のやつ。 見た目の違いで2種類あります(性能は同じ)。

Pebble Steel (Brushed Stainless)
- 出版社/メーカー: Pebble
- メディア: Personal Computers
- この商品を含むブログを見る

Pebble Smartwatch for iPhone and Android ( ブラック / レッド ) 並行輸入品
- 出版社/メーカー: pebble
- メディア: Wireless Phone Accessory
- この商品を含むブログを見る