SyntaxHighlighter

2016年1月12日火曜日

Pebble Time用のWatchFaceのサンプルを作った。

Pebble Time用のWatchFaceのサンプルを作った。

・画像の表示
・月/日 時:分の表示
・バッテリー残量の表示
・Bluetooth状態の表示/接続・切断時バイブ

と、基本的に欲しい機能を突っ込みました。
ほとんど公式のチュートリアル通りです。


プロジェクトのファイルを置いておくので、CloudPebbleにインポートすれば
あとは背景画像を差し替えるだけで使えると思います。
Pebble Classicでも使えるとは思いますが、動作確認はしていませんし、
動くようにも作っていません。(各オプションがPebble Time用になっています)

ダウンロード


動画を見ながらどうぞ。(3:40から手順解説になります)


以下ソースコード。

#include <pebble.h>
#include "main.h"

//うまくWatchFaceに登録されない時は、一度スマホからこのWatchFaceを削除したり
//UUIDやバージョン、作者名を変更したりすると良い。

//mainウィンドウポインタ
static Window *s_main_window;
//時間表示用文字列レイヤー
static TextLayer *s_time_layer;
static TextLayer *sw_time_layer;

//バッテリー表示レイヤー
static TextLayer *s_bat_layer;

//ビットマップ表示用レイヤー
static BitmapLayer *s_background_layer;
//ビットマップデータポインタ
static GBitmap *s_background_bitmap;

//Bluetoothステータス
static char bt_status[4] = "BT";
//過去のBluetoothステータス
static int bt_st_old = 1;

//バッテリーハンドラ
static void battery_handler(BatteryChargeState new_state) {
   //バッテリー状態取得して表示(ついでにBluetooth接続状態を表示)
  static char s_battery_buffer[32];
  snprintf(s_battery_buffer, sizeof(s_battery_buffer), "Bat: %d%%   %s", new_state.charge_percent,bt_status);
  text_layer_set_text(s_bat_layer, s_battery_buffer);
}

//Bluetoothハンドラ
void bt_handler(bool connected) {
  if (connected) {
      //接続に変化したらバイブ
      if(bt_st_old == 0)
         vibes_short_pulse();
      bt_st_old = 1;
      snprintf(bt_status,4,"BT");
   } else {
      //切断に変化したらバイブ
      if(bt_st_old == 1)
         vibes_short_pulse();
      bt_st_old = 0;
      snprintf(bt_status,4,"--");
  }
   //現在のバッテリーを読む(BT表示)
   battery_handler(battery_state_service_peek());
}

//画面更新
static void update_time() {
  //時刻構造体を得る
  time_t temp = time(NULL);
   //ローカル時刻を得る
  struct tm *tick_time = localtime(&temp);
   
   //文字列バッファを確保し、そこに文字列形式で時刻を得る。
   //24時間表示かどうかで切り替えている。
   static char s_buffer[8];
  strftime(s_buffer, sizeof(s_buffer), clock_is_24h_style() ?
                                          "%H:%M" : "%I:%M", tick_time);
   static char sp_buffer[16];
   snprintf(sp_buffer,16,"%02d/%02d  %s",
   (tick_time->tm_mon+1),
  tick_time->tm_mday,
   s_buffer);

  //テキストレイヤーにセットする
  text_layer_set_text(s_time_layer, sp_buffer);
  text_layer_set_text(sw_time_layer, sp_buffer);


}


//タイマーハンドラ
static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
  update_time();//1分に1回画面更新する
}

//Windowが生成された時
static void main_window_load(Window *window) {   
  //ウィンドウの情報を取得
  Layer *window_layer = window_get_root_layer(window);
  GRect bounds = layer_get_bounds(window_layer);

   //ビットマップデータの読み込み
   //RESOURCESではRESOURCE_ID_を含めない名前で指定する。
   //この場合。IDENTIFIER=BACKGROUND
   s_background_bitmap = gbitmap_create_with_resource(RESOURCE_ID_BACKGROUND);
   //ビットマップレイヤーの作成
   s_background_layer = bitmap_layer_create(bounds);
   //ビットマップレイヤーにビットマップを割り
   bitmap_layer_set_bitmap(s_background_layer, s_background_bitmap);
  //windowレイヤーに子レイヤーとしてビットマップレイヤーを追加
   layer_add_child(window_layer, bitmap_layer_get_layer(s_background_layer));

   //-------------------------------------
   
   //境界付きでテキストレイヤーを作成
  sw_time_layer = text_layer_create(
         //x, y, w , h
      GRect(1, 111, bounds.size.w, 50)

      //PBL_IF_ROUND_ELSE(if_true, if_false)なので、円形ならx=58,角形ならx=52
      //GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50)
   );

  //テキストレイヤーを設定
  text_layer_set_background_color(sw_time_layer, GColorClear);
  text_layer_set_text_color(sw_time_layer, GColorFromHEX(0x000000));
  //text_layer_set_text(s_time_layer, "00:00");
  text_layer_set_font(sw_time_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28));
  text_layer_set_text_alignment(sw_time_layer, GTextAlignmentCenter);

  //windowレイヤーに子レイヤーとしてテキストレイヤーを追加
  layer_add_child(window_layer, text_layer_get_layer(sw_time_layer));
   
   //-------------------------------------
   
  //境界付きでテキストレイヤーを作成
  s_time_layer = text_layer_create(
         //x, y, w , h
      GRect(0, 110, bounds.size.w, 50)

      //PBL_IF_ROUND_ELSE(if_true, if_false)なので、円形ならx=58,角形ならx=52
      //GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50)
   );

  //テキストレイヤーを設定
  text_layer_set_background_color(s_time_layer, GColorClear);
  text_layer_set_text_color(s_time_layer, GColorFromHEX(0xFFFFFF));
  //text_layer_set_text(s_time_layer, "00:00");
   
  text_layer_set_font(s_time_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28));
  text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);

  //windowレイヤーに子レイヤーとしてテキストレイヤーを追加
  layer_add_child(window_layer, text_layer_get_layer(s_time_layer));
   
   //-------------------------------------
   
  //境界付きでテキストレイヤーを作成
  s_bat_layer = text_layer_create(
         //x, y, w , h
      GRect(0, 140, bounds.size.w, 50)

      //PBL_IF_ROUND_ELSE(if_true, if_false)なので、円形ならx=58,角形ならx=52
      //GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50)
   );

  //テキストレイヤーを設定
  text_layer_set_background_color(s_bat_layer, GColorClear);
  text_layer_set_text_color(s_bat_layer, GColorFromHEX(0xFFFFFF));
  //text_layer_set_text(s_time_layer, "00:00");
   
  text_layer_set_font(s_bat_layer, fonts_get_system_font(FONT_KEY_GOTHIC_14));
  text_layer_set_text_alignment(s_bat_layer, GTextAlignmentCenter);

  //windowレイヤーに子レイヤーとしてテキストレイヤーを追加
  layer_add_child(window_layer, text_layer_get_layer(s_bat_layer));
   
   //---------------------
   
   //タイマーサービスに分単位での更新を登録する。
   tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);
   
   //バッテリー状態サービスに登録する
   battery_state_service_subscribe(battery_handler);
   //現在のバッテリーを読む
   battery_handler(battery_state_service_peek());
   
   //Bluetooth接続状態サービスに登録する
   connection_service_subscribe((ConnectionHandlers){
     .pebble_app_connection_handler = bt_handler
  });
}

//Windowが破棄された時
static void main_window_unload(Window *window) {
   //ビットマップデータを破棄
   gbitmap_destroy(s_background_bitmap);
   //ビットマップレイヤーを破棄
   bitmap_layer_destroy(s_background_layer);
   //テキストレイヤーを破棄
  text_layer_destroy(s_time_layer);
}

//Appの読み込み時
static void init() {
  //Windowエレメントを作成し、ポインタに割り付け
  s_main_window = window_create();

   //背景色を黒色に設定
   window_set_background_color(s_main_window, GColorCyan);

  //ウィンドウハンドラを割り付け
  window_set_window_handlers(s_main_window, (WindowHandlers){
    .load = main_window_load,
    .unload = main_window_unload
  });

  //スタックにプッシュし表示。アニメーション有効=true
  window_stack_push(s_main_window, true);
   //この時点でmain_window_loadが呼ばれる?
   
   //時刻を初期設定する。
   update_time();
}

static void deinit() {
  //ウィンドウを破棄
  window_destroy(s_main_window);
}

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

0 件のコメント:

コメントを投稿