mirror of
https://github.com/google/pebble.git
synced 2025-05-04 17:01:40 -04:00
200 lines
6.2 KiB
C
200 lines
6.2 KiB
C
/*
|
|
* Copyright 2024 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "crumbs_layer.h"
|
|
|
|
#include "applib/applib_malloc.auto.h"
|
|
#include "shell/system_theme.h"
|
|
#include "applib/ui/property_animation.h"
|
|
#include "process_management/process_manager.h"
|
|
#include "system/logging.h"
|
|
#include "util/trig.h"
|
|
|
|
typedef struct CrumbsLayerSizeConfig {
|
|
int layer_width;
|
|
int crumb_radius;
|
|
int crumb_spacing;
|
|
int crumb_space_from_top;
|
|
} CrumbsLayerSizeConfig;
|
|
|
|
static const CrumbsLayerSizeConfig s_crumb_configs[NumPreferredContentSizes] = {
|
|
//! @note this is the same as Medium until Small is designed
|
|
[PreferredContentSizeSmall] = {
|
|
.layer_width = 14,
|
|
.crumb_radius = 2,
|
|
.crumb_spacing = 8,
|
|
.crumb_space_from_top = 8,
|
|
},
|
|
[PreferredContentSizeMedium] = {
|
|
.layer_width = 14,
|
|
.crumb_radius = 2,
|
|
.crumb_spacing = 8,
|
|
.crumb_space_from_top = 8,
|
|
},
|
|
[PreferredContentSizeLarge] = {
|
|
.layer_width = 16,
|
|
.crumb_radius = 2,
|
|
.crumb_spacing = 10,
|
|
.crumb_space_from_top = 10,
|
|
},
|
|
//! @note this is the same as Large until ExtraLarge is designed
|
|
[PreferredContentSizeExtraLarge] = {
|
|
.layer_width = 16,
|
|
.crumb_radius = 2,
|
|
.crumb_spacing = 10,
|
|
.crumb_space_from_top = 10,
|
|
},
|
|
};
|
|
|
|
static const CrumbsLayerSizeConfig *prv_crumb_config(void) {
|
|
const PreferredContentSize runtime_platform_default_size =
|
|
system_theme_get_default_content_size_for_runtime_platform();
|
|
return &s_crumb_configs[runtime_platform_default_size];
|
|
}
|
|
|
|
int crumbs_layer_width(void) {
|
|
return prv_crumb_config()->layer_width;
|
|
}
|
|
|
|
static int prv_crumb_x_position(void) {
|
|
return prv_crumb_config()->layer_width / 2;
|
|
}
|
|
|
|
static int prv_crumb_radius(void) {
|
|
return prv_crumb_config()->crumb_radius;
|
|
}
|
|
|
|
static int prv_crumb_spacing(void) {
|
|
return prv_crumb_config()->crumb_spacing;
|
|
}
|
|
|
|
static int prv_crumb_space_from_top(void) {
|
|
return prv_crumb_config()->crumb_space_from_top;
|
|
}
|
|
|
|
static int prv_crumb_maximum_count(void) {
|
|
// NOTE: Was originally:
|
|
// static const int MAX_CRUMBS = 16; // 168 / (4px diameter + 4px in between each)
|
|
// However that math literally doesn't add up, it would've been 20 like that.
|
|
// I'm going to just return 16 all the time like we used to, but leave a "correct" version
|
|
// commented out.
|
|
// return (PBL_DISPLAY_HEIGHT - prv_crumb_space_from_top()) / prv_crumb_spacing();
|
|
return 16;
|
|
}
|
|
|
|
static void prv_crumbs_layer_update_proc_rect(Layer *layer, GContext *ctx) {
|
|
const int crumb_radius = prv_crumb_radius();
|
|
const int crumb_spacing = prv_crumb_spacing();
|
|
const int xpos = prv_crumb_x_position();
|
|
|
|
GPoint p = GPoint(xpos, crumb_radius + prv_crumb_space_from_top());
|
|
CrumbsLayer *cl = (CrumbsLayer *)layer;
|
|
graphics_context_set_fill_color(ctx, cl->bg_color);
|
|
graphics_fill_rect(ctx, &layer->bounds);
|
|
|
|
for (int i = cl->level; i > 0; --i) {
|
|
p.x = xpos + (cl->crumbs_x_increment / i);
|
|
graphics_context_set_fill_color(ctx, cl->fg_color);
|
|
graphics_fill_circle(ctx, p, crumb_radius);
|
|
p.y += crumb_spacing;
|
|
}
|
|
}
|
|
|
|
static void prv_crumbs_layer_update_proc_round(Layer *layer, GContext *ctx) {
|
|
CrumbsLayer *cl = (CrumbsLayer *)layer;
|
|
|
|
|
|
graphics_context_set_fill_color(ctx, cl->bg_color);
|
|
// TODO: remove stroke color again, once it's been fixed in fill_radial
|
|
graphics_context_set_stroke_color(ctx, cl->bg_color);
|
|
|
|
|
|
// compensate for problems with rounding errors and physical display shape
|
|
const uint16_t overdraw = 2;
|
|
graphics_fill_radial(ctx, grect_inset(layer->bounds, GEdgeInsets(-overdraw)),
|
|
GOvalScaleModeFillCircle, crumbs_layer_width(), 0, TRIG_MAX_ANGLE);
|
|
}
|
|
|
|
void crumbs_layer_set_level(CrumbsLayer *crumbs_layer, int level) {
|
|
const int max_crumbs = prv_crumb_maximum_count();
|
|
if (level > max_crumbs) {
|
|
PBL_LOG(LOG_LEVEL_WARNING, "exceeded max number of crumbs");
|
|
level = max_crumbs;
|
|
}
|
|
crumbs_layer->level = level;
|
|
layer_mark_dirty((Layer *)crumbs_layer);
|
|
}
|
|
|
|
void crumbs_layer_init(CrumbsLayer *crumbs_layer, const GRect *frame, GColor bg_color,
|
|
GColor fg_color) {
|
|
layer_init(&crumbs_layer->layer, frame);
|
|
crumbs_layer->level = 0;
|
|
crumbs_layer->fg_color = fg_color;
|
|
crumbs_layer->bg_color = bg_color;
|
|
const LayerUpdateProc update_proc = PBL_IF_RECT_ELSE(prv_crumbs_layer_update_proc_rect,
|
|
prv_crumbs_layer_update_proc_round);
|
|
layer_set_update_proc(&crumbs_layer->layer, update_proc);
|
|
}
|
|
|
|
CrumbsLayer *crumbs_layer_create(GRect frame, GColor bg_color, GColor fg_color) {
|
|
// Note: Not yet exported for 3rd party applications so no padding needed
|
|
CrumbsLayer *cl = applib_malloc(sizeof(CrumbsLayer));
|
|
if (cl) {
|
|
crumbs_layer_init(cl, &frame, fg_color, bg_color);
|
|
}
|
|
|
|
return cl;
|
|
}
|
|
|
|
void crumbs_layer_deinit(CrumbsLayer *crumbs_layer) {
|
|
if (crumbs_layer == NULL) {
|
|
return;
|
|
}
|
|
|
|
layer_deinit((Layer *)crumbs_layer);
|
|
}
|
|
|
|
void crumbs_layer_destroy(CrumbsLayer *crumbs_layer) {
|
|
crumbs_layer_deinit(crumbs_layer);
|
|
applib_free(crumbs_layer);
|
|
}
|
|
|
|
int16_t prv_x_getter(void *subject) {
|
|
CrumbsLayer *crumbs_layer = subject;
|
|
return crumbs_layer->crumbs_x_increment;
|
|
}
|
|
|
|
void prv_x_setter(void *subject, int16_t int16) {
|
|
CrumbsLayer *crumbs_layer = subject;
|
|
crumbs_layer->crumbs_x_increment = int16;
|
|
}
|
|
|
|
static const PropertyAnimationImplementation s_prop_impl = {
|
|
.base = {
|
|
.update = (AnimationUpdateImplementation)property_animation_update_int16,
|
|
},
|
|
.accessors = {
|
|
.getter.int16 = prv_x_getter,
|
|
.setter.int16 = prv_x_setter,
|
|
},
|
|
};
|
|
|
|
Animation *crumbs_layer_get_animation(CrumbsLayer *crumbs_layer) {
|
|
uint16_t from = crumbs_layer->level * 2 * prv_crumb_radius();
|
|
uint16_t to = 0;
|
|
PropertyAnimation *prop_anim = property_animation_create(&s_prop_impl, crumbs_layer, &from, &to);
|
|
return property_animation_get_animation(prop_anim);
|
|
}
|