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
- メディア: 時計
- この商品を含むブログを見る
こちらは古い白黒のやつ。 見た目の違いで2種類あります(性能は同じ)。
Pebble Steel (Brushed Stainless)
- 出版社/メーカー: Pebble
- メディア: Personal Computers
- この商品を含むブログを見る
Pebble Smartwatch for iPhone and Android ( ブラック / レッド ) 並行輸入品
- 出版社/メーカー: pebble
- メディア: Wireless Phone Accessory
- この商品を含むブログを見る