pebble/src/fw/applib/ui/status_bar_layer.h
2025-01-27 11:38:16 -08:00

237 lines
11 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.
*/
#pragma once
#include "applib/app_timer.h"
#include "applib/ui/animation.h"
#include "applib/graphics/gtypes.h"
#include "layer.h"
#include "applib/event_service_client.h"
//! @file status_bar_layer.h
//! @addtogroup UI
//! @{
//! @addtogroup Layer Layers
//! @{
//! @addtogroup StatusBarLayer
//! \brief Layer that serves as a configurable status bar.
//! @{
//! The fixed height of the status bar, including separator height, for all platforms.
#define _STATUS_BAR_LAYER_HEIGHT(plat) PBL_PLATFORM_SWITCH(plat, \
/*aplite*/ 16, \
/*basalt*/ 16, \
/*chalk*/ 24, \
/*diorite*/ 16, \
/*emery*/ 20)
//! The fixed height of the status bar, including separator height
#define STATUS_BAR_LAYER_HEIGHT _STATUS_BAR_LAYER_HEIGHT(PBL_PLATFORM_TYPE_CURRENT)
//! The min width of the status bar
#define STATUS_BAR_LAYER_MIN_WIDTH 35
//! The distance from info_text to right edge of the status bar
#define STATUS_BAR_LAYER_INFO_PADDING 7
//! The vertical offset for the status bar layer
#define STATUS_BAR_LAYER_SEPARATOR_Y_OFFSET 2
//! System wide timeout when reverting back to clock mode from custom text
#define STATUS_BAR_LAYER_TITLE_TIMEOUT 5000
//! The size of the title buffer
#define TITLE_TEXT_BUFFER_SIZE 20
//! The size of the info buffer
#define INFO_TEXT_BUFFER_SIZE 8
//! The max size of the total value of set_info_progress before progress is displayed as percentage
#define MAX_INFO_TOTAL 99
//! Values that are used to indicate the different status bar modes
typedef enum {
//! Default mode. Time display takes priority
StatusBarLayerModeClock = 0,
//! Indicates to the user that something is loading. May or may not manually revert when complete.
StatusBarLayerModeLoading = 1,
//! Custom text with an optional auto-revert to the default mode.
StatusBarLayerModeCustomText = 2
} StatusBarLayerMode;
//! Values that are used to indicate the different status bar separator modes.
typedef enum {
//! The default mode. No separator will be shown.
StatusBarLayerSeparatorModeNone = 0,
//! A dotted separator at the bottom of the status bar.
StatusBarLayerSeparatorModeDotted = 1,
} StatusBarLayerSeparatorMode;
//! The data structure of the StatusBarLayerSeparator
typedef struct StatusBarLayerSeparator {
StatusBarLayerSeparatorMode mode;
//! Separator Animation specific variables will eventually be placed here
} StatusBarLayerSeparator;
//! Configuration of a StatusBarLayer independently from Layer and timer code
typedef struct StatusBarLayerConfig {
char title_text_buffer[TITLE_TEXT_BUFFER_SIZE]; // center title text buffer
char info_text_buffer[INFO_TEXT_BUFFER_SIZE]; // right info text buffer
GColor foreground_color; // default:GColorWhite
GColor background_color; // default:GColorBlack
StatusBarLayerSeparator separator; // default:StatusBarLayerSeparatorModeDotted
StatusBarLayerMode mode; // default:StatusBarLayerModeClock
} StatusBarLayerConfig;
//! renders a status bar as described into a given rectangle
void status_bar_layer_render(GContext *ctx, const GRect *bounds, StatusBarLayerConfig *config);
//! The data structure of a StatusBarLayer.
//! @note a `StatusBarLayer *` can safely be cast to a `Layer *` and can thus be
//! used with all other functions that take a `Layer *` as an argument.
//! <br/>For example, the following is legal:
//! \code{.c}
//! StatusBarLayer status_bar_layer;
//! ...
//! layer_set_hidden((Layer *)&status_bar_layer, true);
//! \endcode
typedef struct StatusBarLayer {
Layer layer;
StatusBarLayerConfig config;
AppTimer *title_timer_id; // timer id for title revert
EventServiceInfo tick_event; // Event service to update the time
int previous_min_of_day;
} StatusBarLayer;
//! Creates a new StatusBarLayer on the heap and initializes it with the default values.
//!
//! * Text color: \ref GColorBlack
//! * Background color: \ref GColorWhite
//! * Frame: `GRect(0, 0, screen_width, STATUS_BAR_LAYER_HEIGHT)`
//! The status bar is automatically marked dirty after this operation.
//! You can call \ref layer_set_frame() to create a StatusBarLayer of a different width.
//! @return A pointer to the StatusBarLayer, which will be allocated to the heap,
//! `NULL` if the StatusBarLayer could not be created
void status_bar_layer_init(StatusBarLayer *status_bar_layer);
//! Creates a new StatusBarLayer on the heap and initializes it with the default values.
//!
//! * Text color: \ref GColorBlack
//! * Background color: \ref GColorWhite
//! * Frame: `GRect(0, 0, screen_width, STATUS_BAR_LAYER_HEIGHT)`
//! The status bar is automatically marked dirty after this operation.
//! You can call \ref layer_set_frame() to create a StatusBarLayer of a different width.
//!
//! \code{.c}
//! // Change the status bar width to make space for the action bar
//! int16_t width = layer_get_bounds(root_layer).size.w - ACTION_BAR_WIDTH;
//! GRect frame = GRect(0, 0, width, STATUS_BAR_LAYER_HEIGHT);
//! layer_set_frame(status_bar_layer_get_layer(status_bar), frame);
//! layer_add_child(root_layer, status_bar_layer_get_layer(status_bar));
//! \endcode
//! @return A pointer to the StatusBarLayer, which will be allocated to the heap,
//! `NULL` if the StatusBarLayer could not be created
StatusBarLayer *status_bar_layer_create(void);
//! Destroys a StatusBarLayer previously created by status_bar_layer_create.
//! @param status_bar_layer The StatusBarLayer to destroy
void status_bar_layer_destroy(StatusBarLayer *status_bar_layer);
//! Deinitializes the StatusBarLayer and frees any caches.
//! @param status_bar_layer The StatusBarLayer to deinitialize
//! @internal
void status_bar_layer_deinit(StatusBarLayer *status_bar_layer);
//! Gets the "root" Layer of the status bar, which is the parent for the sub-
//! layers used for its implementation.
//! @param status_bar_layer Pointer to the StatusBarLayer for which to get the "root" Layer
//! @return The "root" Layer of the status bar.
//! @note The result is always equal to `(Layer *) status_bar_layer`.
Layer *status_bar_layer_get_layer(StatusBarLayer *status_bar_layer);
//! Gets background color of StatusBarLayer
//! @param status_bar_layer The StatusBarLayer of which to get the color
//! @return GColor of background color property
GColor status_bar_layer_get_background_color(const StatusBarLayer *status_bar_layer);
//! Sets the background and foreground colors of StatusBarLayer
//! @param status_bar_layer The StatusBarLayer of which to set the colors
//! @param background The new \ref GColor to set for background
//! @param foreground The new \ref GColor to set for text and other foreground elements
void status_bar_layer_set_colors(StatusBarLayer *status_bar_layer, GColor background,
GColor foreground);
//! Gets foreground color of StatusBarLayer
//! @param status_bar_layer The StatusBarLayer of which to get the color
//! @return GColor of foreground color property
GColor status_bar_layer_get_foreground_color(const StatusBarLayer *status_bar_layer);
//! Sets text for title.
//! @param status_bar_layer - StatusBarLayer to set the title text
//! @param text - text to set as title. This will be copied to an internal buffer.
//! @param revert - go back to clock after STATUS_BAR_LAYER_TITLE_TIMEOUT milliseconds
//! @param animate - animate status bar to bounce in
void status_bar_layer_set_title(StatusBarLayer *status_bar_layer, const char *text, bool revert,
bool animate);
//! Gets title text of StatusBarLayer
//! @param status_bar_layer The StatusBarLayer of which to get the text
//! @return The char pointer to current title text
const char *status_bar_layer_get_title(const StatusBarLayer *status_bar_layer);
//! Resets title text to clock text
//! @param status_bar_layer The StatusBarLayer of which to reset the title to clock
void status_bar_layer_reset_title(void *cb_data);
//! Sets the info section to display arbitrary text
//! @param status_bar_layer The StatusBarLayer of which to set the info text
//! @param text The text to set in the information section, limited to 8 characters
void status_bar_layer_set_info_text(StatusBarLayer *status_bar_layer, const char *text);
//! Sets values for the info section to intelligently represent progress, which
//! can be used for pagination. For a total below 99, a count will be displayed,
//! such as 2/8. For a total greater than 99, a percentage will be displayed.
//! @param status_bar_layer The StatusBarLayer of which to set the info text
//! @param current The current value, such as current page number
//! @param total The total value. A total over MAX_INFO_TOTAL will display as a percentage.
void status_bar_layer_set_info_progress(StatusBarLayer *status_bar_layer, uint16_t current,
uint16_t total);
//! Gets info text of StatusBarLayer
//! @param status_bar_layer The StatusBarLayer of which to get the info text
//! @return The char pointer to current text of info text
const char *status_bar_layer_get_info_text(const StatusBarLayer *status_bar_layer);
//! Resets the text in the info section, clearing the value.
//! @param status_bar_layer The StatusBarLayer of which to clear the info text
void status_bar_layer_reset_info(StatusBarLayer *status_bar_layer);
//! Sets the mode of the StatusBarLayer separator, to help divide it from content
//! @param status_bar_layer The StatusBarLayer of which to set the separator mode
//! @param mode Determines the separator mode
void status_bar_layer_set_separator_mode(StatusBarLayer *status_bar_layer,
StatusBarLayerSeparatorMode mode);
//! Gets the mode of the StatusBarLayer separator
//! @param status_bar_layer The StatusBarLayer of which to get the separator mode
//! @return The current mode of the separator
StatusBarLayerSeparatorMode status_bar_layer_get_separator_mode(
const StatusBarLayer *status_bar_layer);
//! @internal
bool layer_is_status_bar_layer(Layer *layer);
int16_t status_layer_get_title_text_width(StatusBarLayer *status_bar_layer);
//! @} // end addtogroup StatusBarLayer
//! @} // end addtogroup Layer
//! @} // end addtogroup UI