static void layer_update_proc(Layer *layer, GContext *ctx) { int length_red, length_blue, length_green, x, y; GColor bar_color; // Get the framebuffer GBitmap *fb = graphics_capture_frame_buffer(ctx); // Manipulate the image data... GBitmapDataRowInfo info = gbitmap_get_data_row_info(fb, BAR_BEGINNING); length_red = s_temperature * (info.max_x - info.min_x) / RANGE_RED; length_green = s_batt * (info.max_x - info.min_x) / RANGE_GREEN; length_blue = s_pop * (info.max_x - info.min_x) / RANGE_BLUE; int temp_red = length_red + (info.max_x - info.min_x); // int bar_length = info.max_x - info.min_x; // Iterate over desired rows for(y = BAR_BEGINNING; y < BAR_END; y++) { // Get this row's range and data info = gbitmap_get_data_row_info(fb, y); // Iterate over all visible columns if (0 <= length_red) { for(x = info.min_x; x < info.max_x; x++) { bar_color.argb = 0b11000000; if (x < length_red) { bar_color.argb = bar_color.argb | 0b00110000; } if (x < length_green) { bar_color.argb = bar_color.argb | 0b00001100; } if (x < length_blue) { bar_color.argb = bar_color.argb | 0b00000011; } // Manipulate the pixel at x,y set_pixel_color(info, GPoint(x, y), bar_color); } } else { for(x = info.min_x; x < info.max_x; x++) { bar_color.argb = 0b11000000; if (x > temp_red) { bar_color.argb = bar_color.argb | 0b00110000; } if (x < length_green) { bar_color.argb = bar_color.argb | 0b00001100; } if (x < length_blue) { bar_color.argb = bar_color.argb | 0b00000011; } // Manipulate the pixel at x,y set_pixel_color(info, GPoint(x, y), bar_color); } } } // Finally, release the framebuffer graphics_release_frame_buffer(ctx, fb); }
// Creates a transparent mask static void bitmap_make_transparent(GBitmap *bitmap, GBitmap *mask) { GRect bounds = gbitmap_get_bounds(mask); for (int y = bounds.origin.y; y < bounds.origin.y + bounds.size.h; y++) { GBitmapDataRowInfo row_info = gbitmap_get_data_row_info(bitmap, y); GBitmapDataRowInfo row_info_mask = gbitmap_get_data_row_info(mask, y); for (int x = row_info_mask.min_x; x < row_info_mask.max_x; x++) { GColor *pixel = (GColor*)&row_info.data[x]; GColor *pixel_mask = (GColor*)&row_info_mask.data[x]; if (pixel_mask->r != 0x0) { pixel->a = 0x3; } else { pixel->a = 0x0; } } } }
void set_bitmap_pixel_color(GBitmap *bitmap, GBitmapFormat bitmap_format, int y, int x, GColor color) { GRect bounds = gbitmap_get_bounds(bitmap); if (y < 0 || y >= bounds.size.h) { //APP_LOG(APP_LOG_LEVEL_WARNING, "Setting offscreen pixel at (%u, %u) to %x", x, y, color.argb); return; } GBitmapDataRowInfo row = gbitmap_get_data_row_info(bitmap, y); if ((x >= row.min_x) && (x <= row.max_x)) { switch(bitmap_format) { case GBitmapFormat1Bit : row.data[x / 8] ^= (-(gcolor_equal(color, GColorWhite)? 1 : 0) ^ row.data[x / 8]) & (1 << (x % 8)); break; case GBitmapFormat1BitPalette : //TODO break; case GBitmapFormat2BitPalette : //TODO break; case GBitmapFormat4BitPalette : //TODO break; case GBitmapFormat8BitCircular : case GBitmapFormat8Bit : row.data[x] = color.argb; } } }
static void update_proc_round_frame_buffer(Layer *layer, GContext *ctx) { GBitmap *fb = graphics_capture_frame_buffer(ctx); GRect bounds = layer_get_bounds(layer); for(int y = 0; y < bounds.size.h; y++) { GBitmapDataRowInfo info = gbitmap_get_data_row_info(fb, y); for(int x = info.min_x; x < info.max_x; x++) { memset(&info.data[x], rand(), 1); } } graphics_release_frame_buffer(ctx, fb); }
static void bitmap_make_semi_transparent(GBitmap *bitmap) { GRect bounds = gbitmap_get_bounds(bitmap); for (int y = bounds.origin.y; y < bounds.origin.y + bounds.size.h; y++) { GBitmapDataRowInfo row_info = gbitmap_get_data_row_info(bitmap, y); for (int x = row_info.min_x; x < row_info.max_x; x++) { GColor *pixel = (GColor*)&row_info.data[x]; if (pixel->a == 0x3) { //pixel->a = ((x%2 + y%2) % 2) ? 0x2 : 0x1; pixel->a = 0x2; } } } }
GColor get_bitmap_pixel_color(GBitmap *bitmap, GBitmapFormat bitmap_format, int y, int x) { GBitmapDataRowInfo row = gbitmap_get_data_row_info(bitmap, y); switch(bitmap_format) { case GBitmapFormat1Bit : return ((row.data[x / 8] >> (x % 8)) & 1) == 1 ? GColorWhite : GColorBlack; case GBitmapFormat1BitPalette : return get_bitmap_color_from_palette_index(bitmap, ((row.data[x / 8] << (x % 8)) & 128) == 128 ? 1 : 0); case GBitmapFormat2BitPalette : return GColorBlack; //TODO get_color_from_palette_index(bitmap, (row.data[x / 4] >> (x % 4)) & 3); case GBitmapFormat4BitPalette : return GColorBlack; //TODO case GBitmapFormat8BitCircular : case GBitmapFormat8Bit : return (GColor) {.argb = row.data[x] }; } return GColorClear; }
static void prv_set_bitmap_opacity(GBitmap * bitmap, GOpacity opacity) { GRect bounds = gbitmap_get_bounds(bitmap); uint8_t alpha_1 = opacity >> 1; uint8_t alpha_2 = (opacity + 1) >> 1; if (alpha_1 >= 3) { // Save some time if the bitmap isn't actually supposed to be // semi-transparent. You may want to remove this if reusing this code. return; } for (int y = bounds.origin.y; y < bounds.origin.y + bounds.size.h; y++) { GBitmapDataRowInfo row_info = gbitmap_get_data_row_info(bitmap, y); for (int x = row_info.min_x; x < row_info.max_x; x++) { GColor * pixel = (GColor *) &row_info.data[x]; if (pixel->a == 0b11) { pixel->a = ((x + y) % 2) ? alpha_1 : alpha_2; } } } }
static void draw_row_callback(GContext *ctx, Layer *cell_layer, MenuIndex *idx, void *context) { GRect bounds = layer_get_bounds(cell_layer); #if defined(PBL_ROUND) // get info of pixel row in the middle of menu row GBitmap *fb = graphics_capture_frame_buffer(ctx); GPoint sc_coord = layer_convert_point_to_screen(cell_layer, GPoint(0, bounds.size.h/2)); GBitmapDataRowInfo info = gbitmap_get_data_row_info(fb, sc_coord.y); graphics_release_frame_buffer(ctx, fb); // adapt bounds for round displays bounds.origin.x = info.min_x + PADDING; bounds.size.w = info.max_x - info.min_x - PADDING; #endif GRect frame = GRect( bounds.origin.x + ICON_SIZE + 3*PADDING, 0, bounds.size.w - 2*ICON_SIZE - PADDING, bounds.size.h/2 ); // draw direction // expand frame width if countdown on the right is small if(deps_items[idx->row].countdown > 0 && deps_items[idx->row].countdown < 10) { frame.size.w += 10; } graphics_draw_text(ctx, deps_items[idx->row].direction, fonts_get_system_font(FONT_KEY_GOTHIC_14), frame, GTextOverflowModeTrailingEllipsis, GTextAlignmentLeft, NULL); // draw time of scheduled departure plus delay frame.origin.y += 12; graphics_draw_text(ctx, deps_items[idx->row].time, fonts_get_system_font(FONT_KEY_GOTHIC_18), frame, GTextOverflowModeTrailingEllipsis, GTextAlignmentLeft, NULL); // draw time until real time departure frame.origin.x = bounds.origin.x + bounds.size.w - ICON_SIZE - PADDING; frame.origin.y = 0; frame.size.w = ICON_SIZE; frame.size.h = ICON_SIZE; if(deps_items[idx->row].countdown == 0) { // draw icon if departure is imminent char* icon_number; if (strcmp(deps_items[idx->row].icon, "bus") == 0) { icon_number = "1"; } else if (strcmp(deps_items[idx->row].icon, "tram") == 0) { icon_number = "2"; } else if (strcmp(deps_items[idx->row].icon, "train") == 0) { icon_number = "3"; } else if (strcmp(deps_items[idx->row].icon, "boat") == 0) { icon_number = "4"; } else if (strcmp(deps_items[idx->row].icon, "funicular") == 0) { icon_number = "5"; } else if (strcmp(deps_items[idx->row].icon, "cable_car") == 0) { icon_number = "6"; } else { icon_number = ""; } frame.origin.x = bounds.origin.x + bounds.size.w - ICON_SIZE; frame.origin.y = 0; frame.size.w = ICON_SIZE+2; frame.size.h = ICON_SIZE; graphics_draw_text(ctx, icon_number, s_icons, frame, GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL); } else { static char s_buff[16]; if(deps_items[idx->row].countdown > 60) { strncpy(s_buff, ">1h", 16); } else if(deps_items[idx->row].countdown > 0) { snprintf(s_buff, sizeof(s_buff), "%d'", deps_items[idx->row].countdown); } graphics_draw_text(ctx, s_buff, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD), frame, GTextOverflowModeFill, GTextAlignmentRight, NULL); } // draw line icon with colors frame.origin.x = bounds.origin.x + PADDING; frame.origin.y = (bounds.size.h / 2) - (ICON_SIZE / 2); frame.size.w = ICON_SIZE; frame.size.h = ICON_SIZE; GColor color_bg; // correct some coloring switch(deps_items[idx->row].color_bg) { case 9090335 : color_bg = GColorSpringBud; break; case 12703135 : color_bg = GColorInchworm; break; default : color_bg = GColorFromHEX(deps_items[idx->row].color_bg); } GColor color_fg = GColorFromHEX(deps_items[idx->row].color_fg); graphics_context_set_fill_color(ctx, COLOR_FALLBACK(color_bg, GColorClear)); graphics_fill_rect(ctx, frame, 3, GCornersAll); if(!gcolor_equal(color_bg, GColorWhite) || menu_cell_layer_is_highlighted(cell_layer)) { graphics_context_set_stroke_color(ctx, COLOR_FALLBACK(GColorWhite, GColorClear)); } graphics_draw_round_rect(ctx, frame, 3); graphics_context_set_text_color(ctx, COLOR_FALLBACK(color_fg, GColorBlack)); char * name = deps_items[idx->row].name; GFont font; if(strlen(name) == 1) { frame.origin.x += 1; frame.origin.y += 3; /*font = fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD);*/ font = s_helvetic_bold; } else if(strlen(name) == 2) { // correct position if 2nd digit is "1" if (strstr(name+1, "1") != NULL) { frame.origin.x += 2; } frame.origin.y += 3; /*font = fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD);*/ font = s_helvetic_bold; /*if(strlen(name) == 1) { frame.origin.x += 1; }*/ } else if(strlen(name) == 3){ frame.origin.y += 3; font = fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD); } else { frame.origin.y += 6; font = fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD); } graphics_draw_text(ctx, name, font, frame, GTextOverflowModeFill, GTextAlignmentCenter, NULL); }
void clear_framebuffer(void) { for (int i = 0; i < c_viewportHeight; ++i) { GBitmapDataRowInfo row_info = gbitmap_get_data_row_info(frameBufferBitmap, i); memset(row_info.data, 0, c_viewportWidth >> 2); } }