mirror of
https://github.com/google/pebble.git
synced 2025-05-25 04:34:52 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
431
src/fw/applib/ui/layer.h
Normal file
431
src/fw/applib/ui/layer.h
Normal file
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
* 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
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue