きっと、アナログ時計のサンプルがどっかにあるはず…と探してみますと、ありました。
Pebble Developer サイトのBestPracticeページに、Examplesリンクがありまして、その先の GitHub にたくさんのサンプルが!watchfaces – simple_analog とか、まさにこれですね!これ、見てみましょう。こういう Watchfaceです。
ソースもヘッダとCファイル1本だけのシンプルなものです。良いですね。ヘッダでは、短針/長針の形と、各時刻ごとの線の形状を定義しているだけですね。
そしてCファイルのほう。針描画のキモになるのは…これです!
GRect bounds = layer_get_bounds(layer); GPoint center = grect_center_point(&bounds); int16_t second_hand_length = bounds.size.w / 2; time_t now = time(NULL); struct tm *t = localtime(&now); int32_t second_angle = TRIG_MAX_ANGLE * t->tm_sec / 60; GPoint second_hand = { .x = (int16_t)(sin_lookup(second_angle) * (int32_t)second_hand_length / TRIG_MAX_RATIO) + center.x, .y = (int16_t)(-cos_lookup(second_angle) * (int32_t)second_hand_length / TRIG_MAX_RATIO) + center.y, }; // second hand graphics_context_set_stroke_color(ctx, GColorWhite); graphics_draw_line(ctx, second_hand, center);
これ完璧ですね!ここを参考にさせてもらいつつ、長針/短針を線で描画するプログラム書きました。
static void drawArrow(Layer *layer, GContext *ctx) { GRect bounds = layer_get_bounds(layer); GPoint center = grect_center_point(&bounds); int16_t arrow_length = bounds.size.w / 2; time_t now = time(NULL); struct tm *t = localtime(&now); int32_t arrow_angle = 0; for(int index = 0;index < 2;index++) { if( index == 0 ){ //短針 arrow_length = bounds.size.w / 2.5; arrow_angle = (TRIG_MAX_ANGLE * (((t->tm_hour % 12) * 6) + (t->tm_min / 10))) / (12 * 6); graphics_context_set_stroke_color(ctx, GColorBlack); }else{ //長針 arrow_length = bounds.size.w / 2; arrow_angle = TRIG_MAX_ANGLE * t->tm_min / 60; graphics_context_set_stroke_color(ctx, GColorBlack); } GPoint arrow = { .x = (int16_t)(sin_lookup(arrow_angle) * (int32_t)arrow_length / TRIG_MAX_RATIO) + center.x, .y = (int16_t)(-cos_lookup(arrow_angle) * (int32_t)arrow_length / TRIG_MAX_RATIO) + center.y, }; graphics_draw_line(ctx, arrow, center); } }
こいつを layer_update_callback から呼んであげれば…
ただいま、23時35分です!時計っぽくなったよ!
あとは、これ、定期的に更新する仕組みですね。さっきのwatchfaces – simple_analog をもう一度見てみましょう。
むむ、init() のところで、何かやってますね…。
tick_timer_service_subscribe(SECOND_UNIT, handle_second_tick);
これ、デジタル時計の時にやった定期的に呼び出す処理だ!これで何を呼んでいるかというと…
static void handle_second_tick(struct tm *tick_time, TimeUnits units_changed) { layer_mark_dirty(window_get_root_layer(window)); }
ん?これだけ?なんだこれは。 layer_mark_dirtyとは…
void layer_mark_dirty(Layer * layer)
Layerを”dirty”にマークするものらしい。dirtyにマークされたレイヤーは、システムが再描画(update_proc呼び出し)してくれるそうだ。layer_mark_dirtyを呼んだ瞬間に再描画されるわけではなく、非同期で短時間後に再描画されるとのこと。
サンプルプログラムでは1秒に1回これを呼ぶことで、1秒ごとの再描画をしていたのだな。僕の作っているやつは秒針は無いので、1分に1回の再描画でよいってことだ。
tick_timer_service_subscribe(MINUTE_UNIT, handle_minute_tick);
こうか。(関数名も合わせたよ!)
そして、時は動き出す…!