・画像の表示
・月/日 時:分の表示
・バッテリー残量の表示
・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();
}