チュートリアルの先へ(2) : 時計の針・ザ・ワールド!

きっと、アナログ時計のサンプルがどっかにあるはず…と探してみますと、ありました。
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 から呼んであげれば…

pebble7_05

ただいま、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);

こうか。(関数名も合わせたよ!)

pebble7_06

そして、時は動き出す…!