mirror of
https://github.com/google/pebble.git
synced 2025-05-01 15:51:40 -04:00
431 lines
19 KiB
C
431 lines
19 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/graphics/gtypes.h"
|
|
#include "applib/ui/recognizer/recognizer.h"
|
|
#include "applib/ui/recognizer/recognizer_list.h"
|
|
|
|
#include <stdbool.h>
|
|
|
|
struct Layer;
|
|
struct Animation;
|
|
|
|
//! How deep our layer tree is allowed to be.
|
|
#define LAYER_TREE_STACK_SIZE 16
|
|
|
|
//! @file layer.h
|
|
//! @addtogroup UI
|
|
//! @{
|
|
//! @addtogroup Layer Layers
|
|
//! \brief User interface layers for displaying graphic components
|
|
//!
|
|
//! Layers are objects that can be displayed on a Pebble watchapp window, enabling users to see
|
|
//! visual objects, like text or images. Each layer stores the information about its state
|
|
//! necessary to draw or redraw the object that it represents and uses graphics routines along with
|
|
//! this state to draw itself when asked. Layers can be used to display various graphics.
|
|
//!
|
|
//! Layers are the basic building blocks for your application UI. Layers can be nested inside each other.
|
|
//! Every window has a root layer which is always the topmost layer.
|
|
//! You provide a function that is called to draw the content of the layer when needed; or
|
|
//! you can use standard layers that are provided by the system, such as text layer, image layer,
|
|
//! menu layer, action bar layer, and so on.
|
|
//!
|
|
//! The Pebble layer hierarchy is the list of things that need to be drawn to the screen.
|
|
//! Multiple layers can be arranged into a hierarchy. This enables ordering (front to back),
|
|
//! layout and hierarchy. Through relative positioning, visual objects that are grouped together by
|
|
//! adding them into the same layer can be moved all at once. This means that the child layers
|
|
//! will move accordingly. If a parent layer has clipping enabled, all the children will be clipped
|
|
//! to the frame of the parent.
|
|
//!
|
|
//! Pebble OS provides convenience layers with built-in logic for displaying different graphic
|
|
//! components, like text and bitmap layers.
|
|
//!
|
|
//! Refer to the \htmlinclude UiFramework.html (chapter "Layers") for a conceptual overview
|
|
//! of Layers and relevant code examples.
|
|
//!
|
|
//! The Modules listed here contain what can be thought of conceptually as subclasses of Layer. The
|
|
//! listed types can be safely type-casted to `Layer` (or `Layer *` in case of a pointer).
|
|
//! The `layer_...` functions can then be used with the data structures of these subclasses.
|
|
//! <br/>For example, the following is legal:
|
|
//! \code{.c}
|
|
//! TextLayer *text_layer;
|
|
//! ...
|
|
//! layer_set_hidden((Layer *)text_layer, true);
|
|
//! \endcode
|
|
//! @{
|
|
|
|
//! Function signature for a Layer's render callback (the name of the type
|
|
//! is derived from the words 'update procedure').
|
|
//! The system will call the `.update_proc` callback whenever the Layer needs
|
|
//! to be rendered.
|
|
//! @param layer The layer that needs to be rendered
|
|
//! @param ctx The destination graphics context to draw into
|
|
//! @see \ref Graphics
|
|
//! @see \ref layer_set_update_proc()
|
|
typedef void (*LayerUpdateProc)(struct Layer *layer, GContext* ctx);
|
|
|
|
typedef void (*PropertyChangedProc)(struct Layer *layer);
|
|
|
|
//! Layer contains point override function. This can replace the default implementation of
|
|
//! \ref layer_contains_point using the \ref layer_set_contains_point_override call. The override
|
|
//! function should return true if the point should be deemed within the layer and false if not.
|
|
//! The point is relative to the frame origin of the layer
|
|
//! @param layer affected layer
|
|
//! @param point point relative to the frame origin of the layer
|
|
//! @return true if point should be considered to be contained within the layer
|
|
typedef bool (*LayerContainsPointOverride)(const struct Layer *layer, const GPoint *point);
|
|
|
|
//! Data structure of a Layer.
|
|
//! It contains the following:
|
|
//! * geometry (frame, bounds)
|
|
//! * clipping, hidden flags
|
|
//! * a reference to its window
|
|
//! * a reference to its render callback
|
|
//! * references that constitute the layer hierarchy
|
|
typedef struct Layer {
|
|
/* Geometry */
|
|
|
|
//! @internal
|
|
//! Internal box bounds
|
|
GRect bounds;
|
|
|
|
//! @internal
|
|
//! Box bounds relative to parent layer coordinates
|
|
GRect frame;
|
|
|
|
union {
|
|
uint8_t flags;
|
|
struct {
|
|
bool clips:1;
|
|
bool hidden:1;
|
|
bool has_data:1;
|
|
bool is_highlighted:1; //!< Indicates the highlight status of a \ref MenuLayer cell
|
|
};
|
|
};
|
|
|
|
/* Layer tree */
|
|
struct Layer *next_sibling;
|
|
struct Layer *parent;
|
|
struct Layer *first_child;
|
|
|
|
struct Window *window;
|
|
|
|
//! Drawing callback
|
|
//! can be NULL if layer doesn't draw anything
|
|
LayerUpdateProc update_proc;
|
|
|
|
//! Property changed callback
|
|
PropertyChangedProc property_changed_proc;
|
|
|
|
#if CAPABILITY_HAS_TOUCHSCREEN
|
|
//! List of attached recognizers
|
|
RecognizerList recognizer_list;
|
|
|
|
//! Override callback to determine whether a layer contains a point
|
|
LayerContainsPointOverride contains_point_override;
|
|
#endif
|
|
} Layer;
|
|
|
|
typedef struct DataLayer {
|
|
Layer layer;
|
|
|
|
uint8_t data[];
|
|
} DataLayer;
|
|
|
|
//! Initializes the given layer and sets its frame and bounds.
|
|
//! Default values:
|
|
//! * `bounds` : origin (0, 0) and a size equal to the frame that is passed in.
|
|
//! * `clips` : `true`
|
|
//! * `hidden` : `false`
|
|
//! * `update_proc` : `NULL` (draws nothing)
|
|
//! @param layer The layer to initialize
|
|
//! @param frame The frame at which the layer should be initialized.
|
|
//! @param data_size The size (in bytes) of memory to initialize after the layer struct.
|
|
//! @see \ref layer_set_frame()
|
|
//! @see \ref layer_set_bounds()
|
|
void layer_init(Layer *layer, const GRect *frame);
|
|
|
|
//! Creates a layer on the heap and sets its frame and bounds.
|
|
//! Default values:
|
|
//! * `bounds` : origin (0, 0) and a size equal to the frame that is passed in.
|
|
//! * `clips` : `true`
|
|
//! * `hidden` : `false`
|
|
//! * `update_proc` : `NULL` (draws nothing)
|
|
//! @param frame The frame at which the layer should be initialized.
|
|
//! @see \ref layer_set_frame()
|
|
//! @see \ref layer_set_bounds()
|
|
//! @return A pointer to the layer. `NULL` if the layer could not
|
|
//! be created
|
|
Layer* layer_create(GRect frame);
|
|
|
|
//! Creates a layer on the heap with extra space for callback data, and set its frame andbounds.
|
|
//! Default values:
|
|
//! * `bounds` : origin (0, 0) and a size equal to the frame that is passed in.
|
|
//! * `clips` : `true`
|
|
//! * `hidden` : `false`
|
|
//! * `update_proc` : `NULL` (draws nothing)
|
|
//! @param frame The frame at which the layer should be initialized.
|
|
//! @param data_size The size (in bytes) of memory to allocate for callback data.
|
|
//! @see \ref layer_create()
|
|
//! @see \ref layer_set_frame()
|
|
//! @see \ref layer_set_bounds()
|
|
//! @return A pointer to the layer. `NULL` if the layer could not be created
|
|
Layer* layer_create_with_data(GRect frame, size_t data_size);
|
|
|
|
void layer_deinit(Layer *layer);
|
|
|
|
//! Destroys a layer previously created by layer_create
|
|
void layer_destroy(Layer* layer);
|
|
|
|
//! @internal
|
|
//! Renders a tree of layers to a graphics context
|
|
void layer_render_tree(Layer *root, GContext *ctx);
|
|
|
|
//! @internal
|
|
//! Process the PropertyChangedProc callback for a tree of layers
|
|
void layer_property_changed_tree(Layer *root);
|
|
|
|
//! Marks the complete layer as "dirty", awaiting to be asked by the system to redraw itself.
|
|
//! Typically, this function is called whenever state has changed that affects what the layer
|
|
//! is displaying.
|
|
//! * The layer's `.update_proc` will not be called before this function returns,
|
|
//! but will be called asynchronously, shortly.
|
|
//! * Internally, a call to this function will schedule a re-render of the window that the
|
|
//! layer belongs to. In effect, all layers in that window's layer hierarchy will be asked to redraw.
|
|
//! * If an earlier re-render request is still pending, this function is a no-op.
|
|
//! @param layer The layer to mark dirty
|
|
void layer_mark_dirty(Layer *layer);
|
|
|
|
//! Sets the layer's render function.
|
|
//! The system will call the `update_proc` automatically when the layer needs to redraw itself, see
|
|
//! also \ref layer_mark_dirty().
|
|
//! @param layer Pointer to the layer structure.
|
|
//! @param update_proc Pointer to the function that will be called when the layer needs to be rendered.
|
|
//! Typically, one performs a series of drawing commands in the implementation of the `update_proc`,
|
|
//! see \ref Drawing, \ref PathDrawing and \ref TextDrawing.
|
|
void layer_set_update_proc(Layer *layer, LayerUpdateProc update_proc);
|
|
|
|
//! Sets the frame of the layer, which is it's bounding box relative to the coordinate
|
|
//! system of its parent layer.
|
|
//! The size of the layer's bounds will be extended automatically, so that the bounds
|
|
//! cover the new frame.
|
|
//! @param layer The layer for which to set the frame
|
|
//! @param frame The new frame
|
|
//! @see \ref layer_set_bounds()
|
|
void layer_set_frame_by_value(Layer *layer, GRect frame);
|
|
void layer_set_frame(Layer *layer, const GRect *frame);
|
|
|
|
//! Gets the frame of the layer, which is it's bounding box relative to the coordinate
|
|
//! system of its parent layer.
|
|
//! If the frame has changed, \ref layer_mark_dirty() will be called automatically.
|
|
//! @param layer The layer for which to get the frame
|
|
//! @return The frame of the layer
|
|
//! @see layer_set_frame
|
|
GRect layer_get_frame_by_value(const Layer *layer);
|
|
void layer_get_frame(const Layer *layer, GRect *frame);
|
|
|
|
//! Sets the bounds of the layer, which is it's bounding box relative to its frame.
|
|
//! If the bounds has changed, \ref layer_mark_dirty() will be called automatically.
|
|
//! @param layer The layer for which to set the bounds
|
|
//! @param bounds The new bounds
|
|
//! @see \ref layer_set_frame()
|
|
void layer_set_bounds_by_value(Layer *layer, GRect bounds);
|
|
void layer_set_bounds(Layer *layer, const GRect *bounds);
|
|
|
|
//! Gets the bounds of the layer
|
|
//! @param layer The layer for which to get the bounds
|
|
//! @return The bounds of the layer
|
|
//! @see layer_set_bounds
|
|
GRect layer_get_bounds_by_value(const Layer *layer);
|
|
void layer_get_bounds(const Layer *layer, GRect *bounds);
|
|
|
|
//! Gets the window that the layer is currently attached to.
|
|
//! @param layer The layer for which to get the window
|
|
//! @return The window that this layer is currently attached to, or `NULL` if it has
|
|
//! not been added to a window's layer hierarchy.
|
|
//! @see \ref window_get_root_layer()
|
|
//! @see \ref layer_add_child()
|
|
struct Window *layer_get_window(const Layer *layer);
|
|
|
|
//! Removes the layer from its current parent layer
|
|
//! If removed successfully, the child's parent layer will be marked dirty
|
|
//! automatically.
|
|
//! @param child The layer to remove
|
|
void layer_remove_from_parent(Layer *child);
|
|
|
|
//! Removes child layers from given layer
|
|
//! If removed successfully, the child's parent layer will be marked dirty
|
|
//! automatically.
|
|
//! @param parent The layer from which to remove all child layers
|
|
void layer_remove_child_layers(Layer *parent);
|
|
|
|
//! Adds the child layer to a given parent layer, making it appear
|
|
//! in front of its parent and in front of any existing child layers
|
|
//! of the parent.
|
|
//! If the child layer was already part of a layer hierarchy, it will
|
|
//! be removed from its old parent first.
|
|
//! If added successfully, the parent (and children) will be marked dirty
|
|
//! automatically.
|
|
//! @param parent The layer to which to add the child layer
|
|
//! @param child The layer to add to the parent layer
|
|
void layer_add_child(Layer *parent, Layer *child);
|
|
|
|
//! Inserts the layer as a sibling behind another layer. If the layer to insert was
|
|
//! already part of a layer hierarchy, it will be removed from its old parent first.
|
|
//! The below_layer has to be a child of a parent layer,
|
|
//! otherwise this function will be a noop.
|
|
//! If inserted successfully, the parent (and children) will be marked dirty
|
|
//! automatically.
|
|
//! @param layer_to_insert The layer to insert into the hierarchy
|
|
//! @param below_sibling_layer The layer that will be used as the sibling layer
|
|
//! above which the insertion will take place
|
|
void layer_insert_below_sibling(Layer *layer_to_insert, Layer *below_sibling_layer);
|
|
|
|
//! Inserts the layer as a sibling in front of another layer.
|
|
//! The above_layer has to be a child of a parent layer,
|
|
//! otherwise this function will be a noop.
|
|
//! If inserted successfully, the parent (and children) will be marked dirty
|
|
//! automatically.
|
|
//! @param layer_to_insert The layer to insert into the hierarchy
|
|
//! @param above_sibling_layer The layer that will be used as the sibling layer
|
|
//! below which the insertion will take place
|
|
void layer_insert_above_sibling(Layer *layer_to_insert, Layer *above_sibling_layer);
|
|
|
|
//! Sets the visibility of the layer.
|
|
//! If the visibility has changed, \ref layer_mark_dirty() will be called automatically
|
|
//! on the parent layer.
|
|
//! @param layer The layer for which to set the visibility
|
|
//! @param hidden Supply `true` to make the layer hidden, or `false` to make it
|
|
//! non-hidden.
|
|
void layer_set_hidden(Layer *layer, bool hidden);
|
|
|
|
//! Gets the visibility of the layer.
|
|
//! @param layer The layer for which to get the visibility
|
|
//! @return True if the layer is hidden, false if it is not hidden.
|
|
bool layer_get_hidden(const Layer *layer);
|
|
|
|
//! Sets whether clipping is enabled for the layer. If enabled, whatever the layer _and
|
|
//! its children_ will draw using their `.update_proc` callbacks, will be clipped by the
|
|
//! this layer's frame.
|
|
//! If the clipping has changed, \ref layer_mark_dirty() will be called automatically.
|
|
//! @param layer The layer for which to set the clipping property
|
|
//! @param clips Supply `true` to make the layer clip to its frame, or `false`
|
|
//! to make it non-clipping.
|
|
void layer_set_clips(Layer *layer, bool clips);
|
|
|
|
//! Gets whether clipping is enabled for the layer. If enabled, whatever the layer _and
|
|
//! its children_ will draw using their `.update_proc` callbacks, will be clipped by the
|
|
//! this layer's frame.
|
|
//! @param layer The layer for which to get the clipping property
|
|
//! @return True if clipping is enabled for the layer, false if clipping is not enabled for
|
|
//! the layer.
|
|
bool layer_get_clips(const Layer *layer);
|
|
|
|
//! Gets the data from a layer that has been created with an extra data region.
|
|
//! @param layer The layer to get the data region from.
|
|
//! @return A void pointer to the data region.
|
|
void* layer_get_data(const Layer *layer);
|
|
|
|
//! Converts a point from the layer's local coordinate system to screen coordinates.
|
|
//! @note If the layer isn't part of the view hierarchy the result is undefined.
|
|
//! @param layer The view whose coordinate system will be used to convert the value to the screen.
|
|
//! @param point A point specified in the local coordinate system (bounds) of the layer.
|
|
//! @return The point converted to the coordinate system of the screen.
|
|
GPoint layer_convert_point_to_screen(const Layer *layer, GPoint point);
|
|
|
|
//! Converts a rectangle from the layer's local coordinate system to screen coordinates.
|
|
//! @note If the layer isn't part of the view hierarchy the result is undefined.
|
|
//! @param layer The view whose coordinate system will be used to convert the value to the screen.
|
|
//! @param rect A rectangle specified in the local coordinate system (bounds) of the layer.
|
|
//! @return The rectangle converted to the coordinate system of the screen.
|
|
GRect layer_convert_rect_to_screen(const Layer *layer, GRect rect);
|
|
|
|
//! @internal
|
|
//! Get the layer's frame in global coordinates
|
|
//! @param layer The layer whose global frame you seek
|
|
//! @param[out] global_frame_out GRect pointer to write the global frame to
|
|
void layer_get_global_frame(const Layer *layer, GRect *global_frame_out);
|
|
|
|
//! Get the largest unobstructed bounds rectangle of a layer.
|
|
//! @param layer The layer for which to get the unobstructed bounds.
|
|
//! @return The unobstructed bounds of the layer.
|
|
//! @see UnobstructedArea
|
|
GRect layer_get_unobstructed_bounds_by_value(const Layer *layer);
|
|
void layer_get_unobstructed_bounds(const Layer *layer, GRect *bounds_out);
|
|
|
|
//! Return whether a point is contained within the bounds of a layer. Can be overridden by
|
|
//! \ref layer_set_contains_point_override. Default behavior is to check that the point is within
|
|
//! layer's bounds.
|
|
//! @param layer layer to be tested
|
|
//! @param point point relative to the frame origin of the layer
|
|
//! @return true if the point is contained within the bounds of the layer
|
|
bool layer_contains_point(const Layer *layer, const GPoint *point);
|
|
|
|
//! Override the function layer_contains_point with a custom function
|
|
void layer_set_contains_point_override(Layer *layer, LayerContainsPointOverride override);
|
|
|
|
//! @internal
|
|
//! Traverse the tree starting at \ref node and find the layer in the tree which:
|
|
//! - contains the specified point,
|
|
//! - has no children which also contain the point
|
|
//! - is the last layer added to it's parent if any of its siblings match the above criteria, too.
|
|
//! When traversing, a branch will only be entered if that node layer contains the point (so each
|
|
//! layer down to the first with no children or more recently added siblings must contain the
|
|
//! point).
|
|
//! \note \ref layer_contains_point is used to perform the test as to whether the point is contained
|
|
//! within the layer, which can be overridden with custom implementations
|
|
//! @param node layer to start the traversal at
|
|
//! @param point point that must be contained within any found layer
|
|
//! @return the layer found, otherwise NULL, if no layers contain the point
|
|
Layer *layer_find_layer_containing_point(const Layer *node, const GPoint *point);
|
|
|
|
//! @note Do not export until touch is supported in the SDK!
|
|
//! Attach a recognizer to a layer
|
|
//! @param layer \ref Layer to which to attach \ref Recognizer
|
|
//! @param recognizer \ref Recognizer to attach
|
|
void layer_attach_recognizer(Layer *layer, Recognizer *recognizer);
|
|
|
|
//! @note Do not export until touch is supported in the SDK!
|
|
//! Detach a recognizer from a layer
|
|
//! @param layer \ref Layer from which to remove \ref Recognizer
|
|
//! @param recognizer \ref Recognizer to detach
|
|
void layer_detach_recognizer(Layer *layer, Recognizer *recognizer);
|
|
|
|
//! @note Do not export until touch is supported in the SDK!
|
|
//! Get the recognizers attached to a layer
|
|
//! @param layer \ref Layer from which to get recognizers
|
|
//! @return recognizer list
|
|
RecognizerList *layer_get_recognizer_list(const Layer *layer);
|
|
|
|
//! Return whether or \a layer is a descendant of \a potential_ancestor
|
|
//! @param layer check this layer to see if any of it's ancestors are \a potential_ancestor
|
|
//! @param potential_ancestor check to see if this layer is an ancestor of \a layer
|
|
//! match
|
|
//! @return true if \a layer is a descendant of \a potential_ancestor
|
|
bool layer_is_descendant(const Layer *layer, const Layer *potential_ancestor);
|
|
|
|
//! @internal
|
|
//! Common Scrolling directions
|
|
typedef enum {
|
|
ScrollDirectionDown = -1,
|
|
ScrollDirectionNone = 0,
|
|
ScrollDirectionUp = 1
|
|
} ScrollDirection;
|
|
|
|
//! @} // end addtogroup Layer
|
|
//! @} // end addtogroup UI
|
|
|