Pebble Timeで社畜用Watch Faceを作ってみた

あむちょです。

新しくなったPebble用watch face(文字盤)をいくつか作ったまま放置してたのでとりあえずリリース

PR アプリ作ってます
ad maruta

Pebble Timeってなんですかって人はこちら。丸型スマートウォッチPebble Time Roundのレビュー

今回公開したのは、旧型Pebbleでも作った社畜用Watch Faceです。旧型PebbleはこちらPebbleで社畜専用のWatch Faceを作る

時間に追われる社畜向けに、通勤時間の7~9の間、針の動きが大きくなるので急いで出社しましょう。

Pebble Time Watch Face 「Rush Hour」

rushhour rect rushHour

現状丸型のPebble Time Roundしか対応してないので、気がむいたら角形のPebble Timeにもそのうち対応させるかも。対応させました。

ここからダウンロードできます。Pebble Watch Face 「Rush Hour」

作り方

web上での開発が可能になり、めんどくさい開発環境を整える必要がなくなったけど、やっぱりc言語で書いてターミナルからコンパイル操作をするのはなんか落ち着きますね。

画像背景にパスで秒針を描画してるだけです。1秒毎に再描画しているのでバッテリーの消費がちょっと心配。

とりあえずソースコード。

#include 

#define EMPTY_SLOT -1

static Window *window;
static GBitmap *image;
static BitmapLayer *image_layer;
static int image_state=EMPTY_SLOT;

static Layer *layer;

static int hour;
static int min;
static int sec = 32;

static GPath *hour_path;
static GPath *min_path;

#define ROUND_HOUR 50 //44
#define ROUND_MIN 64
#define ROUND_SEC 70

#if defined(PBL_RECT)
    #define WIDTH 144
    #define HEIGHT 168
#elif defined(PBL_ROUND)
    #define WIDTH 180
    #define HEIGHT 180
#endif

static const GPathInfo POINTS_HOUR = {
    3, (GPoint []){
        {-8,10},
        {8, 10},
        {0,-ROUND_HOUR}
      /*  {6, -ROUND_HOUR},
        {-6, -ROUND_HOUR} */
    }
};
static const GPathInfo POINTS_MIN = {
    4, (GPoint []){
        {-5,10},
        {5, 10},
        {5, -ROUND_MIN},
        {-5, -ROUND_MIN}
    }
};

static void update_proc(Layer *layer, GContext *ctx) {
    
    graphics_context_set_fill_color(ctx, GColorWhite);
    graphics_context_set_stroke_color(ctx, GColorBlack);
    
    float angle;
    
//min
    if(min < 35)angle = TRIG_MAX_ANGLE*( (float)min*3.6/360);
    else if(min < 45)angle = TRIG_MAX_ANGLE*( (126.0+((float)min-35.0)*18)/360);
    else{
        angle = TRIG_MAX_ANGLE*( (306.0+((float)min-45.0)*3.6)/360 );
    }
    
    gpath_rotate_to(min_path, angle);
    gpath_draw_filled(ctx, min_path);
    gpath_draw_outline(ctx,min_path);
    
//hour
    if(hour < 7)angle = TRIG_MAX_ANGLE*( ((float)hour+(float)min/60)*18/360 );
    else if(hour < 9)angle = TRIG_MAX_ANGLE*( (126.0+(((float)hour+(float)min/60)-7.0)*90)/360 );
    else{
        angle = TRIG_MAX_ANGLE*( (306.0+(((float)hour+(float)min/60-9.0)*18))/360 );
    }
    
    gpath_rotate_to(hour_path, angle);
    gpath_draw_filled(ctx, hour_path);
    gpath_draw_outline(ctx,hour_path);
    
//sec
    if(sec < 35)angle = TRIG_MAX_ANGLE*( (float)sec*3.6/360);
    else if(sec < 45)angle = TRIG_MAX_ANGLE*( (126.0+((float)sec-35.0)*18)/360); else{ angle = TRIG_MAX_ANGLE*( (306.0+((float)sec-45.0)*3.6)/360 ); } GPoint secondHand; //int32_t second_angle = TRIG_MAX_ANGLE*sec/60; secondHand.y = (int16_t)(-cos_lookup(angle)*(int32_t)ROUND_SEC/TRIG_MAX_RATIO)+HEIGHT/2; secondHand.x = (int16_t)(sin_lookup(angle)*(int32_t)ROUND_SEC/TRIG_MAX_RATIO)+WIDTH/2; // second hand graphics_context_set_stroke_width(ctx,2); graphics_context_set_stroke_color(ctx, GColorRed); //graphics_draw_line(ctx, secondHand, GPoint(180/2,180/2)); graphics_draw_line(ctx, secondHand, GPoint(WIDTH/2-(sin_lookup(angle)*8/TRIG_MAX_RATIO),HEIGHT/2-(-cos_lookup(angle)*8/TRIG_MAX_RATIO))); // dot in the middle graphics_context_set_fill_color(ctx, GColorBlack); //graphics_fill_rect(ctx, GRect(180/2-1, 180/2-1, 3, 3), 0, GCornerNone); graphics_fill_circle(ctx, GPoint(WIDTH/2, HEIGHT/2), 2); } static void update_time(struct tm* tick_time){ hour = tick_time->tm_hour%12;
    min = tick_time->tm_min;
    sec = tick_time->tm_sec;
    
    //layer_mark_dirty(window_get_root_layer(window));
    layer_mark_dirty(layer);
}

static void handle_second_tick(struct tm* tick_time, TimeUnits units_changed) {
    
    update_time(tick_time);
    
}

static void window_load(Window *window) {
    Layer *window_layer = window_get_root_layer(window);
    GRect bounds = layer_get_bounds(window_layer);
    
    //image
    image_state=1;
    image = gbitmap_create_with_resource(RESOURCE_ID_IMAGE);
    image_layer = bitmap_layer_create(bounds);
    bitmap_layer_set_bitmap(image_layer, image);
    layer_add_child(window_layer, bitmap_layer_get_layer(image_layer));

    //layer
    layer = layer_create(bounds);
    layer_set_update_proc(layer, update_proc);
    layer_add_child(window_layer, layer);
    
    //path
    hour_path = gpath_create(&POINTS_HOUR);
    min_path = gpath_create(&POINTS_MIN);
    
    GRect centerRect =(GRect){.origin = {0,0}, .size = {bounds.size.w,bounds.size.h}};
    const GPoint center = grect_center_point(&centerRect);
    gpath_move_to(hour_path, center);
    gpath_move_to(min_path, center);
    
    time_t now = time(NULL);
    struct tm *tick_time = localtime(&now);
    
    update_time(tick_time);
    
}


static void window_unload(Window *window) {

    layer_destroy(layer);

}

static void init(void) {
    window = window_create();
    window_set_background_color(window, GColorBlack);
    window_set_window_handlers(window, (WindowHandlers) {
        .load = window_load,
        .unload = window_unload,
    });
    const bool animated = true;
    window_stack_push(window, animated);
    
    tick_timer_service_subscribe(SECOND_UNIT, &handle_second_tick);

}

static void deinit(void) {

    tick_timer_service_unsubscribe();
    
    if (image_state != EMPTY_SLOT) {
        layer_remove_from_parent(bitmap_layer_get_layer(image_layer));
        bitmap_layer_destroy(image_layer);
        gbitmap_destroy(image);
        image_state = EMPTY_SLOT;
    }
    
    gpath_destroy(hour_path);
    gpath_destroy(min_path);
    
    window_destroy(window);
}

int main(void) {
  init();

  app_event_loop();
  deinit();
}

時間の所得で

hour = tick_time->tm_hour%12;

としているのはユーザーが24時間表示にしている時の対策です。

眠たい

とりあえずさぼってた時期にやってた事を順番にブログに投稿しようかとおもったけど

すでにちょっとめんどくさくなってきた。

コメント