Exemple #1
0
void destroy_chrono_objects() {
  app_log(APP_LOG_LEVEL_INFO, __FILE__, __LINE__, "destroy_chrono_objects");

  layer_destroy(chrono_dial_layer);
  bwd_destroy(&chrono_dial_white);
  bwd_destroy(&chrono_dial_black);

  if (chrono_digital_window != NULL) {
    window_destroy(chrono_digital_window);
    chrono_digital_window = NULL;
  }

#ifdef ENABLE_CHRONO_MINUTE_HAND
  layer_destroy(chrono_minute_layer);
#endif
#ifdef ENABLE_CHRONO_SECOND_HAND
  layer_destroy(chrono_second_layer);
#endif
#ifdef ENABLE_CHRONO_TENTH_HAND
  layer_destroy(chrono_tenth_layer);
#endif
  hand_cache_destroy(&chrono_minute_cache);
  hand_cache_destroy(&chrono_second_cache);
  hand_cache_destroy(&chrono_tenth_cache);
}
Exemple #2
0
void draw_chrono_dial(GContext *ctx) {
  //  app_log(APP_LOG_LEVEL_INFO, __FILE__, __LINE__, "draw_chrono_dial");
  
  if (config.chrono_dial != CDM_off) {
#ifdef PBL_PLATFORM_APLITE
    BitmapWithData chrono_dial_black;
    if (chrono_dial_shows_tenths) {
      chrono_dial_black = rle_bwd_create(RESOURCE_ID_CHRONO_DIAL_TENTHS_BLACK);
    } else {
      chrono_dial_black = rle_bwd_create(RESOURCE_ID_CHRONO_DIAL_HOURS_BLACK);
    }
    if (chrono_dial_black.bitmap == NULL) {
      bwd_destroy(&chrono_dial_black);
      trigger_memory_panic(__LINE__);
    }
#endif  // PBL_PLATFORM_APLITE

    // In Basalt, we only load the "white" image.
    if (chrono_dial_white.bitmap == NULL) {
      if (chrono_dial_shows_tenths) {
        chrono_dial_white = rle_bwd_create(RESOURCE_ID_CHRONO_DIAL_TENTHS_WHITE);
      } else {
        chrono_dial_white = rle_bwd_create(RESOURCE_ID_CHRONO_DIAL_HOURS_WHITE);
      }
      if (chrono_dial_white.bitmap == NULL) {
        trigger_memory_panic(__LINE__);
        return;
      }
    
      // We apply the color scheme as needed.
      remap_colors_clock(&chrono_dial_white);
    }
  
    int x = chrono_tenth_hand_def.place_x - chrono_dial_size.w / 2;
    int y = chrono_tenth_hand_def.place_y - chrono_dial_size.h / 2;
    
    GRect destination = GRect(x, y, chrono_dial_size.w, chrono_dial_size.h);

#ifdef PBL_PLATFORM_APLITE
    graphics_context_set_compositing_mode(ctx, draw_mode_table[config.draw_mode ^ APLITE_INVERT].paint_fg);
    graphics_draw_bitmap_in_rect(ctx, chrono_dial_black.bitmap, destination);
    graphics_context_set_compositing_mode(ctx, draw_mode_table[config.draw_mode ^ APLITE_INVERT].paint_bg);
    graphics_draw_bitmap_in_rect(ctx, chrono_dial_white.bitmap, destination);
#else  // PBL_PLATFORM_APLITE
    graphics_context_set_compositing_mode(ctx, GCompOpSet);
    graphics_draw_bitmap_in_rect(ctx, chrono_dial_white.bitmap, destination);
#endif  // PBL_PLATFORM_APLITE

    if (!keep_assets) {
      bwd_destroy(&chrono_dial_white);
    }
#ifdef PBL_PLATFORM_APLITE
    bwd_destroy(&chrono_dial_black);
#endif  // PBL_PLATFORM_APLITE
  }
}
void destroy_bluetooth_bitmaps() {
  bwd_destroy(&bluetooth_disconnected);
  bwd_destroy(&bluetooth_connected);
  bwd_destroy(&bluetooth_mask);

#ifndef PBL_PLATFORM_APLITE
  bwd_destroy(&quiet_time);
  bwd_destroy(&quiet_time_mask);
#endif  // PBL_PLATFORM_APLITE
}
Exemple #4
0
// Release any memory held within a HandCache structure.
void hand_cache_destroy(struct HandCache *hand_cache) {
  bwd_destroy(&hand_cache->image);
  bwd_destroy(&hand_cache->mask);
  int gi;
  for (gi = 0; gi < HAND_CACHE_MAX_GROUPS; ++gi) {
    if (hand_cache->path[gi] != NULL) {
      gpath_destroy(hand_cache->path[gi]);
      hand_cache->path[gi] = NULL;
    }
  }
}
Exemple #5
0
// Updates any runtime settings as needed when the config changes.
void apply_config() {
  app_log(APP_LOG_LEVEL_INFO, __FILE__, __LINE__, "apply_config");

  // Reset the memory panic count when we get a new config setting.
  // Maybe the user knows what he's doing.
  memory_panic_count = 0;

  if (face_index != config.face_index) {
    // Update the face bitmap if it's changed.
    face_index = config.face_index;
    bwd_destroy(&clock_face);

    // Also move any layers to their new position on this face.
    for (int i = 0; i < NUM_DATE_WINDOWS; ++i) {
      const struct IndicatorTable *window = &date_windows[i][config.face_index];
      layer_set_frame((Layer *)date_window_layers[i], GRect(window->x - 19, window->y - 8, 39, 19));
    }

    {
      const struct IndicatorTable *window = &battery_table[config.face_index];
      move_battery_gauge(window->x, window->y, window->invert, window->opaque);
    }
    {
      const struct IndicatorTable *window = &bluetooth_table[config.face_index];
      move_bluetooth_indicator(window->x, window->y, window->invert, window->opaque);
    }
  }

  if (display_lang != config.display_lang) {
    // Unload the day font if it changes with the language.
    if (date_lang_font != NULL && (display_lang == -1 || lang_table[display_lang].font_index != lang_table[config.display_lang].font_index)) {
      app_log(APP_LOG_LEVEL_INFO, __FILE__, __LINE__, "apply_config unload date_lang_font %p", date_lang_font);
      safe_unload_custom_font(&date_lang_font);
    }

    // Reload the weekday, month, and ampm names from the appropriate
    // language resource.
    fill_date_names(date_names, NUM_DATE_NAMES, date_names_buffer, DATE_NAMES_MAX_BUFFER, lang_table[config.display_lang].date_name_id);

    display_lang = config.display_lang;
  }

#ifdef SUPPORT_MOON
  // Reload the moon bitmap just for good measure.  Maybe the user
  // changed the draw mode or the lunar direction.
  bwd_destroy(&moon_bitmap);
#endif  // SUPPORT_MOON

  layer_mark_dirty(clock_face_layer);

  reset_tick_timer();
}
Exemple #6
0
// Draws the frame and optionally fills the background of the current date window.
void draw_date_window_background(GContext *ctx, unsigned int fg_draw_mode, unsigned int bg_draw_mode, bool opaque_layer) {
  if (opaque_layer || bg_draw_mode != fg_draw_mode) {
    if (date_window_mask.bitmap == NULL) {
      date_window_mask = rle_bwd_create(RESOURCE_ID_DATE_WINDOW_MASK);
      if (date_window_mask.bitmap == NULL) {
	trigger_memory_panic(__LINE__);
        return;
      }
    }
    graphics_context_set_compositing_mode(ctx, draw_mode_table[bg_draw_mode].paint_mask);
    graphics_draw_bitmap_in_rect(ctx, date_window_mask.bitmap, date_window_box);
  }
  
  if (date_window.bitmap == NULL) {
    date_window = rle_bwd_create(RESOURCE_ID_DATE_WINDOW);
    if (date_window.bitmap == NULL) {
      bwd_destroy(&date_window_mask);
      trigger_memory_panic(__LINE__);
      return;
    }
  }

  graphics_context_set_compositing_mode(ctx, draw_mode_table[fg_draw_mode].paint_fg);
  graphics_draw_bitmap_in_rect(ctx, date_window.bitmap, date_window_box);
}
Exemple #7
0
// Destroys the objects created by create_objects().
void destroy_objects() {
  app_log(APP_LOG_LEVEL_INFO, __FILE__, __LINE__, "destroy_objects");
  window_stack_pop_all(false);
  layer_destroy(clock_face_layer);
  clock_face_layer = NULL;
  bwd_destroy(&clock_face);
  face_index = -1;

#ifdef MAKE_CHRONOGRAPH
  destroy_chrono_objects();
#endif  // MAKE_CHRONOGRAPH

  deinit_battery_gauge();
  deinit_bluetooth_indicator();

  for (int i = 0; i < NUM_DATE_WINDOWS; ++i) {
    layer_destroy(date_window_layers[i]);
    date_window_layers[i] = NULL;
  }

  bwd_destroy(&date_window);
  bwd_destroy(&date_window_mask);

#ifdef SUPPORT_MOON
  bwd_destroy(&moon_bitmap);
#endif  // SUPPORT_MOON
  
  layer_destroy(minute_layer);
  layer_destroy(hour_layer);
  layer_destroy(second_layer);

  hand_cache_destroy(&hour_cache);
  hand_cache_destroy(&minute_cache);
  hand_cache_destroy(&second_cache);

  if (date_lang_font != NULL) {
    safe_unload_custom_font(&date_lang_font);
  }
  display_lang = -1;

  window_destroy(window);
  window = NULL;
}
Exemple #8
0
void load_chrono_dial() {
#ifdef PBL_PLATFORM_APLITE
  bwd_destroy(&chrono_dial_white);
  bwd_destroy(&chrono_dial_black);
  if (chrono_dial_shows_tenths) {
    chrono_dial_white = rle_bwd_create(RESOURCE_ID_CHRONO_DIAL_TENTHS_WHITE);
    chrono_dial_black = rle_bwd_create(RESOURCE_ID_CHRONO_DIAL_TENTHS_BLACK);
  } else {
    chrono_dial_white = rle_bwd_create(RESOURCE_ID_CHRONO_DIAL_HOURS_WHITE);
    chrono_dial_black = rle_bwd_create(RESOURCE_ID_CHRONO_DIAL_HOURS_BLACK);
  }
  if (chrono_dial_white.bitmap == NULL || chrono_dial_black.bitmap == NULL) {
    bwd_destroy(&chrono_dial_white);
    bwd_destroy(&chrono_dial_black);
    trigger_memory_panic(__LINE__);
  }
#else  // PBL_PLATFORM_APLITE
  // In Basalt, we only load the "white" image.
  bwd_destroy(&chrono_dial_white);
  if (chrono_dial_shows_tenths) {
    chrono_dial_white = rle_bwd_create(RESOURCE_ID_CHRONO_DIAL_TENTHS_WHITE);
  } else {
    chrono_dial_white = rle_bwd_create(RESOURCE_ID_CHRONO_DIAL_HOURS_WHITE);
  }
  if (chrono_dial_white.bitmap == NULL) {
    bwd_destroy(&chrono_dial_white);
    trigger_memory_panic(__LINE__);
    return;
  }

  // We apply the color-inverting mode if necessary.
  uint8_t xor_argb8 = config.draw_mode ? 0x3f : 0x00;
  bwd_adjust_colors(&chrono_dial_white, 0xff, 0x00, xor_argb8);
#endif  // PBL_PLATFORM_APLITE
}
Exemple #9
0
void destroy_chrono_objects() {
  app_log(APP_LOG_LEVEL_INFO, __FILE__, __LINE__, "destroy_chrono_objects");

  if (chrono_digital_window != NULL) {
    window_destroy(chrono_digital_window);
    chrono_digital_window = NULL;
  }

  hand_cache_destroy(&chrono_minute_cache);
  hand_cache_destroy(&chrono_second_cache);
  hand_cache_destroy(&chrono_tenth_cache);

  bwd_destroy(&chrono_dial_white);
}
Exemple #10
0
void compute_chrono_hands(unsigned int ms, struct HandPlacement *placement) {
  unsigned int chrono_ms = get_chrono_ms(ms);

  bool chrono_dial_wants_tenths = true;
  switch (config.chrono_dial) {
  case CDM_off:
    break;

  case CDM_tenths:
    chrono_dial_wants_tenths = true;
    break;

  case CDM_hours:
    chrono_dial_wants_tenths = false;
    break;

  case CDM_dual:
    // In dual mode, we show either tenths or hours, depending on the
    // amount of elapsed time.  Less than 30 minutes shows tenths.
    chrono_dial_wants_tenths = (chrono_ms < 30 * 60 * 1000);
    break;
  }

  if (chrono_dial_shows_tenths != chrono_dial_wants_tenths) {
    // The dial has changed states; reload and redraw it.
    chrono_dial_shows_tenths = chrono_dial_wants_tenths;
    bwd_destroy(&chrono_dial_white);
    bwd_destroy(&chrono_dial_black);
    if (chrono_dial_layer != NULL) {
      layer_mark_dirty(chrono_dial_layer);
    }
  }
    
#ifdef ENABLE_CHRONO_MINUTE_HAND
  // The chronograph minute hand rolls completely around in 30
  // minutes (not 60).
  {
    unsigned int use_ms = chrono_ms % (1800 * 1000);
    placement->chrono_minute_hand_index = ((NUM_STEPS_CHRONO_MINUTE * use_ms) / (1800 * 1000)) % NUM_STEPS_CHRONO_MINUTE;
  }
#endif  // ENABLE_CHRONO_MINUTE_HAND

#ifdef ENABLE_CHRONO_SECOND_HAND
  {
    // Avoid overflowing the integer arithmetic by pre-constraining
    // the ms value to the appropriate range.
    unsigned int use_ms = chrono_ms % (60 * 1000);
    if (!config.sweep_seconds) {
      // Also constrain to an integer second if we've not enabled sweep-second resolution.
      use_ms = (use_ms / 1000) * 1000;
    }
    placement->chrono_second_hand_index = ((NUM_STEPS_CHRONO_SECOND * use_ms) / (60 * 1000));
  }
#endif  // ENABLE_CHRONO_SECOND_HAND

#ifdef ENABLE_CHRONO_TENTH_HAND
  if (config.chrono_dial == CDM_off) {
    // Don't keep updating this hand if we're not showing it anyway.
    placement->chrono_tenth_hand_index = 0;
  } else {
    if (chrono_dial_shows_tenths) {
      // Drawing tenths-of-a-second.
      if (chrono_data.running && !chrono_data.lap_paused) {
	// We don't actually show the tenths time while the chrono is running.
	placement->chrono_tenth_hand_index = 0;
      } else {
	// We show the tenths time when the chrono is stopped or showing
	// the lap time.
	unsigned int use_ms = chrono_ms % 1000;
	// Truncate to the previous 0.1 seconds (100 ms), just to
	// make the dial easier to read.
	use_ms = 100 * (use_ms / 100);
	placement->chrono_tenth_hand_index = ((NUM_STEPS_CHRONO_TENTH * use_ms) / (1000)) % NUM_STEPS_CHRONO_TENTH;
      }
    } else {
      // Drawing hours.  12-hour scale.
      unsigned int use_ms = chrono_ms % (12 * SECONDS_PER_HOUR * 1000);
      placement->chrono_tenth_hand_index = ((NUM_STEPS_CHRONO_TENTH * use_ms) / (12 * SECONDS_PER_HOUR * 1000)) % NUM_STEPS_CHRONO_TENTH;
    }
  }
#endif  // ENABLE_CHRONO_TENTH_HAND
}
Exemple #11
0
// Called once per epoch (e.g. once per second, or once per minute) to
// compute the new positions for all of the hands on the watch based
// on the current time.  This does not actually draw the hands; it
// only computes which position each hand should hold, and it marks
// the appropriate layers dirty, to eventually redraw the hands that
// have moved since the last call.
void update_hands(struct tm *time) {
  struct HandPlacement new_placement = current_placement;

  compute_hands(time, &new_placement);
  if (new_placement.hour_hand_index != current_placement.hour_hand_index) {
    current_placement.hour_hand_index = new_placement.hour_hand_index;
    layer_mark_dirty(hour_layer);
  }

  if (new_placement.minute_hand_index != current_placement.minute_hand_index) {
    current_placement.minute_hand_index = new_placement.minute_hand_index;
    layer_mark_dirty(minute_layer);
  }

  if (new_placement.second_hand_index != current_placement.second_hand_index) {
    current_placement.second_hand_index = new_placement.second_hand_index;
    layer_mark_dirty(second_layer);
  }

  if (new_placement.hour_buzzer != current_placement.hour_buzzer) {
    current_placement.hour_buzzer = new_placement.hour_buzzer;
    if (config.hour_buzzer) {
      // The hour has changed; ring the buzzer if it's enabled.
      vibes_short_pulse();
    }
  }

  // Make sure the sweep timer is fast enough to capture the second
  // hand.
  sweep_timer_ms = 1000;
  if (config.sweep_seconds) {
    sweep_timer_ms = sweep_seconds_ms;
  }

#ifdef MAKE_CHRONOGRAPH
  update_chrono_hands(&new_placement);
#endif  // MAKE_CHRONOGRAPH

  // If any of the date window properties changes, update all of the
  // date windows.  (We cheat and only check the fastest changing
  // element, and the date value just in case someone's playing games
  // with the clock.)
  if (new_placement.ampm_value != current_placement.ampm_value ||
      new_placement.date_value != current_placement.date_value) {
    current_placement.day_index = new_placement.day_index;
    current_placement.month_index = new_placement.month_index;
    current_placement.date_value = new_placement.date_value;
    current_placement.year_value = new_placement.year_value;
    current_placement.ampm_value = new_placement.ampm_value;

    // Shorthand for the below for loop.  This achieves the same thing.
    layer_mark_dirty(clock_face_layer);
    /*
    for (int i = 0; i < NUM_DATE_WINDOWS; ++i) {
      layer_mark_dirty(date_window_layers[i]);
    }
    */
  }

#ifdef SUPPORT_MOON
  // Also check the lunar phase, in a separate check from the other
  // date windows, so it doesn't necessarily have to wait till
  // midnight to flip over to the next phase.
  if (new_placement.lunar_phase != current_placement.lunar_phase) {
    current_placement.lunar_phase = new_placement.lunar_phase;
    bwd_destroy(&moon_bitmap);
    layer_mark_dirty(clock_face_layer);
  }
#endif  // SUPPORT_MOON
}
Exemple #12
0
// Draws a given hand on the face, using the bitmap structures.
void draw_bitmap_hand(struct HandCache *hand_cache, struct HandDef *hand_def, int hand_index, GContext *ctx) {
  if (hand_cache->bitmap_hand_index != hand_index) {
    // Force a new bitmap.
    if (hand_cache->image.bitmap != NULL) {
      bwd_destroy(&hand_cache->image);
    }
    if (hand_cache->mask.bitmap != NULL) {
      bwd_destroy(&hand_cache->mask);
    }
    hand_cache->bitmap_hand_index = hand_index;
  }

  struct BitmapHandTableRow *hand = &hand_def->bitmap_table[hand_index];
  int bitmap_index = hand->bitmap_index;
  struct BitmapHandCenterRow *lookup = &hand_def->bitmap_centers[bitmap_index];

  int hand_resource_id = hand_def->resource_id + bitmap_index;
  int hand_resource_mask_id = hand_def->resource_mask_id + bitmap_index;
 
  if (hand_def->resource_id == hand_def->resource_mask_id) {
    // The hand does not have a mask.  Draw the hand on top of the scene.
    if (hand_cache->image.bitmap == NULL) {
      if (hand_def->use_rle) {
	hand_cache->image = rle_bwd_create(hand_resource_id);
      } else {
	hand_cache->image = png_bwd_create(hand_resource_id);
      }
      if (hand_cache->image.bitmap == NULL) {
        hand_cache_destroy(hand_cache);
	trigger_memory_panic(__LINE__);
        return;
      }
      hand_cache->cx = lookup->cx;
      hand_cache->cy = lookup->cy;
    
      if (hand->flip_x) {
        // To minimize wasteful resource usage, if the hand is symmetric
        // we can store only the bitmaps for the right half of the clock
        // face, and flip them for the left half.
        flip_bitmap_x(hand_cache->image.bitmap, &hand_cache->cx);
      }
    
      if (hand->flip_y) {
        // We can also do this vertically.
        flip_bitmap_y(hand_cache->image.bitmap, &hand_cache->cy);
      }
    }
      
    // We make sure the dimensions of the GRect to draw into
    // are equal to the size of the bitmap--otherwise the image
    // will automatically tile.
    GRect destination = hand_cache->image.bitmap->bounds;
    
    // Place the hand's center point at place_x, place_y.
    destination.origin.x = hand_def->place_x - hand_cache->cx;
    destination.origin.y = hand_def->place_y - hand_cache->cy;
    
    // Specify a compositing mode to make the hands overlay on top of
    // each other, instead of the background parts of the bitmaps
    // blocking each other.

    if (hand_def->paint_black) {
      // Painting foreground ("white") pixels as black.
      graphics_context_set_compositing_mode(ctx, draw_mode_table[config.draw_mode].paint_black);
    } else {
      // Painting foreground ("white") pixels as white.
      graphics_context_set_compositing_mode(ctx, draw_mode_table[config.draw_mode].paint_white);
    }
      
    graphics_draw_bitmap_in_rect(ctx, hand_cache->image.bitmap, destination);
    
  } else {
    // The hand has a mask, so use it to draw the hand opaquely.
    if (hand_cache->image.bitmap == NULL) {
      if (hand_def->use_rle) {
	hand_cache->image = rle_bwd_create(hand_resource_id);
	hand_cache->mask = rle_bwd_create(hand_resource_mask_id);
      } else {
	hand_cache->image = png_bwd_create(hand_resource_id);
	hand_cache->mask = png_bwd_create(hand_resource_mask_id);
      }
      if (hand_cache->image.bitmap == NULL || hand_cache->mask.bitmap == NULL) {
        hand_cache_destroy(hand_cache);
	trigger_memory_panic(__LINE__);
        return;
      }
      hand_cache->cx = lookup->cx;
      hand_cache->cy = lookup->cy;
    
      if (hand->flip_x) {
        // To minimize wasteful resource usage, if the hand is symmetric
        // we can store only the bitmaps for the right half of the clock
        // face, and flip them for the left half.
        flip_bitmap_x(hand_cache->image.bitmap, &hand_cache->cx);
        flip_bitmap_x(hand_cache->mask.bitmap, NULL);
      }
    
      if (hand->flip_y) {
        // We can also do this vertically.
        flip_bitmap_y(hand_cache->image.bitmap, &hand_cache->cy);
        flip_bitmap_y(hand_cache->mask.bitmap, NULL);
      }
    }
    
    GRect destination = hand_cache->image.bitmap->bounds;
    
    destination.origin.x = hand_def->place_x - hand_cache->cx;
    destination.origin.y = hand_def->place_y - hand_cache->cy;

    graphics_context_set_compositing_mode(ctx, draw_mode_table[config.draw_mode].paint_white);
    graphics_draw_bitmap_in_rect(ctx, hand_cache->mask.bitmap, destination);
    
    graphics_context_set_compositing_mode(ctx, draw_mode_table[config.draw_mode].paint_black);
    graphics_draw_bitmap_in_rect(ctx, hand_cache->image.bitmap, destination);
  }
}