/* * 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 "click.h" #include "applib/graphics/gtypes.h" #include "applib/ui/layer.h" #include "applib/ui/recognizer/recognizer.h" #include "applib/ui/recognizer/recognizer_manager.h" struct Window; struct WindowStack; //! @file window.h //! @addtogroup UI //! @{ //! @addtogroup Window //! \brief The basic building block of the user interface //! //! Windows are the top-level elements in the UI hierarchy and the basic building blocks for a Pebble //! UI. A single window is always displayed at a time on Pebble, with the exception of when animating //! from one window to the other, which, in that case, is managed by the window stack. You can stack //! windows on top of each other, but only the topmost window will be visible. //! //! Users wearing a Pebble typically interact with the content and media displayed in a window, clicking //! and pressing buttons on the watch, depending on what they see and wish to respond to in a window. //! //! Windows serve to display a hierarchy of layers on the screen and handle user input. When a window is //! visible, its root Layer (and all its child layers) are drawn onto the screen automatically. //! //! You need a window, which always fills the entire screen, to display images, text, and graphics in //! your Pebble app. A layer by itself doesn’t display on Pebble; it must be in the current window’s //! layer hierarchy to be visible. //! //! The Window Stack serves as the global manager of what window is presented and makes sure that input //! events are forwarded to the topmost window. //! //! Refer to the \htmlinclude UiFramework.html (chapter "Window") for a conceptual //! overview of Window, the Window Stack and relevant code examples. //! @{ //! Function signature for a handler that deals with transition events of a window. //! @see WindowHandlers //! @see \ref window_set_window_handlers() typedef void (*WindowHandler)(struct Window *window); //! WindowHandlers //! These handlers are called by the \ref WindowStack as windows get pushed on / popped. //! All these handlers use \ref WindowHandler as their function signature. //! @see \ref window_set_window_handlers() //! @see \ref WindowStack typedef struct WindowHandlers { //! Called when the window is pushed to the screen when it's not loaded. //! This is a good moment to do the layout of the window. WindowHandler load; //! Called when the window comes on the screen (again). E.g. when //! second-top-most window gets revealed (again) after popping the top-most //! window, but also when the window is pushed for the first time. This is a //! good moment to start timers related to the window, or reset the UI, etc. WindowHandler appear; //! Called when the window leaves the screen, e.g. when another window //! is pushed, or this window is popped. Good moment to stop timers related //! to the window. WindowHandler disappear; //! Called when the window is deinited, but could be used in the future to //! free resources bound to windows that are not on screen. WindowHandler unload; } WindowHandlers; //! Data structure of a window. typedef struct Window { //! The root layer of the window. //! By default, the `.update_proc` will draw the background color of the window. Layer layer; //! The handlers that are called by the system whenever there are window transitions //! happening (load, appear, disappear and unload). //! @see \ref window_set_window_handlers() WindowHandlers window_handlers; //! The callback that will be called by the system to get the ClickRecognizer s //! set up for this window. //! @see \ref window_set_click_config_provider() //! @see \ref window_set_click_config_provider_with_context() ClickConfigProvider click_config_provider; //! Pointer to application specific data that will be passed into the //! `click_config_provider` callback. //! @see \ref window_set_click_config_provider_with_context() void *click_config_context; //! @internal //! Pointer to application specific data that the app can assign to a window. //! @see \ref window_set_user_data() and \ref window_get_user_data() void *user_data; //! The background color that will be used to fill the background of the window. //! @see \ref window_set_background_color() GColor8 background_color; bool is_render_scheduled:1; bool on_screen:1; bool is_loaded:1; bool overrides_back_button:1; bool is_fullscreen:1; bool in_click_config_provider:1; //! @internal //! If a click config provider was changed while the window was covered by a modal, //! this flag is used to indicate that it should be called when uncovered. bool is_waiting_for_click_config:1; //! @internal //! If the window has configured its click config provider. This flag is used to automatically //! click configure a window if a modal from above relinquishes focus either by going off screen //! or becoming unfocusable. This is necessary because windows can be unfocusable, thus whether //! they are on screen does not indicate whether their click has been configured. bool is_click_configured:1; //! @internal //! If the window can visually expose window stacks below it. This property decides whether the //! window stack would expose window stacks below it. A window stack is transparent if the top //! window in the window stack is transparent. Windows that are not the top window in their //! respective window stack are never shown, therefore transparent windows can only expose //! the top windows of window stacks below it, not windows within the same window stack. //! @note Currently, the app window stack is the lowest stack, is_transparent has no affect on //! app windows. bool is_transparent:1; //! @internal //! If the window passes input to the next window stack with a top focusable window. A window //! stack is unfocusable if the top window in the window stack is unfocusable. Windows that are //! not the top window in their respective window stack never receive input, therefore //! unfocusable windows can only pass input to the top windows of window stacks below it, not //! windows within the same window stack. bool is_unfocusable:1; //! @internal //! Back pointer to the window stack that this Window is residing on. //! @see \ref WindowStack struct WindowStack *parent_window_stack; const char* debug_name; } Window; #ifdef RELEASE #define WINDOW_NAME(x) "" #else #define WINDOW_NAME(x) x #endif //! Initializes a window and resets its members to the default values: //! //! * Background color : `GColorWhite` //! * Root layer's `update_proc` : function that fills the window's background using `background_color`. //! * `click_config_provider` : `NULL` //! * `window_handlers` : all `NULL` //! @param window The window to initialize //! @param debug_name The window's debug name void window_init(Window *window, const char* debug_name); //! Creates a new Window on the heap and initializes it with the default values. //! //! * Background color : `GColorWhite` //! * Root layer's `update_proc` : function that fills the window's background using `background_color`. //! * `click_config_provider` : `NULL` //! * `window_handlers` : all `NULL` //! @return A pointer to the window. `NULL` if the window could not //! be created Window* window_create(void); //! Destroys a Window previously created by window_create. void window_destroy(Window* window); //! Deinitializes the window. //! Removes the window from the screen, removes its child layers from the root layer and //! finally calls the `.unload` window handler. //! @note This function removes the window from the screen, even though it might still //! be presented. Normally, the window stack will call this function automatically //! after a window has been popped (removed) from the window stack. //! @param window The window to deinitialize void window_deinit(Window *window); //! Sets the click configuration provider callback function on the window. //! This will automatically setup the input handlers of the window as well to use //! the click recognizer subsystem. //! @param window The window for which to set the click config provider //! @param click_config_provider The callback that will be called to configure the click recognizers with the window //! @see Clicks //! @see ClickConfigProvider void window_set_click_config_provider(Window *window, ClickConfigProvider click_config_provider); //! Same as window_set_click_config_provider(), but will assign a custom context pointer //! (instead of the window pointer) that will be passed into the ClickHandler click event handlers. //! @param window The window for which to set the click config provider //! @param click_config_provider The callback that will be called to configure the click recognizers with the window //! @param context Pointer to application specific data that will be passed to the click configuration provider callback (defaults to the window). //! @see Clicks //! @see window_set_click_config_provider void window_set_click_config_provider_with_context(Window *window, ClickConfigProvider click_config_provider, void *context); //! Set the context that will be passed to handlers for the given button's events. By default the context passed to handlers //! is equal to the \ref ClickConfigProvider context (defaults to the window). //! @note Must be called from within the \ref ClickConfigProvider. //! @param button_id The button to set the context for. //! @param context Set the context that will be passed to handlers for the given button's events. void window_set_click_context(ButtonId button_id, void *context); //! Subscribe to single click events. //! @note Must be called from the \ref ClickConfigProvider. //! @note \ref window_single_click_subscribe() and \ref window_single_repeating_click_subscribe() conflict, and cannot both be used on the same button. //! @note When there is a multi_click and/or long_click setup, there will be a delay before the single click //! @param button_id The button events to subscribe to. //! @param handler The \ref ClickHandler to fire on this event. //! handler will get fired. On the other hand, when there is no multi_click nor long_click setup, the single click handler will fire directly on button down. //! @see ButtonId //! @see Clicks //! @see window_single_repeating_click_subscribe void window_single_click_subscribe(ButtonId button_id, ClickHandler handler); //! Subscribe to single click event, with a repeat interval. A single click is detected every time "repeat_interval_ms" has been reached. //! @note Must be called from the \ref ClickConfigProvider. //! @note \ref window_single_click_subscribe() and \ref window_single_repeating_click_subscribe() conflict, and cannot both be used on the same button. //! @note The back button cannot be overridden with a repeating click. //! @param button_id The button events to subscribe to. //! @param repeat_interval_ms When holding down, how many milliseconds before the handler is fired again. //! A value of 0ms means "no repeat timer". The minimum is 30ms, and values below will be disregarded. //! If there is a long-click handler subscribed on this button, `repeat_interval_ms` will not be used. //! @param handler The \ref ClickHandler to fire on this event. //! @see window_single_click_subscribe void window_single_repeating_click_subscribe(ButtonId button_id, uint16_t repeat_interval_ms, ClickHandler handler); //! Subscribe to multi click events. //! @note Must be called from the \ref ClickConfigProvider. //! @param button_id The button events to subscribe to. //! @param min_clicks Minimum number of clicks before handler is fired. Defaults to 2. //! @param max_clicks Maximum number of clicks after which the click counter is reset. A value of 0 means use "min" also as "max". //! @param timeout The delay after which a sequence of clicks is considered finished, and the click counter is reset. A value of 0 means to use the system default 300ms. //! @param last_click_only Defaults to false. When true, only the handler for the last multi-click is called. //! @param handler The \ref ClickHandler to fire on this event. Fired for multi-clicks, as "filtered" by the `last_click_only`, `min`, and `max` parameters. void window_multi_click_subscribe(ButtonId button_id, uint8_t min_clicks, uint8_t max_clicks, uint16_t timeout, bool last_click_only, ClickHandler handler); //! Subscribe to long click events. //! @note Must be called from the \ref ClickConfigProvider. //! @note The back button cannot be overridden with a long click. //! @param button_id The button events to subscribe to. //! @param delay_ms Milliseconds after which "handler" is fired. A value of 0 means to use the system default 500ms. //! @param down_handler The \ref ClickHandler to fire as soon as the button has been held for `delay_ms`. This may be NULL to have no down handler. //! @param up_handler The \ref ClickHandler to fire on the release of a long click. This may be NULL to have no up handler. void window_long_click_subscribe(ButtonId button_id, uint16_t delay_ms, ClickHandler down_handler, ClickHandler up_handler); //! Subscribe to raw click events. //! @note Must be called from within the \ref ClickConfigProvider. //! @note The back button cannot be overridden with a raw click. //! @param button_id The button events to subscribe to. //! @param down_handler The \ref ClickHandler to fire as soon as the button has been pressed. This may be NULL to have no down handler. //! @param up_handler The \ref ClickHandler to fire on the release of the button. This may be NULL to have no up handler. //! @param context If this context is not NULL, it will override the general context. void window_raw_click_subscribe(ButtonId button_id, ClickHandler down_handler, ClickHandler up_handler, void *context); //! Gets the current click configuration provider of the window. //! @param window The window for which to get the click config provider ClickConfigProvider window_get_click_config_provider(const Window *window); //! Gets the current click configuration provider context of the window. //! @param window The window for which to get the click config provider context void *window_get_click_config_context(Window *window); //! @internal //! This function replaces \ref window_set_window_handlers_by_value in order to change the handlers //! parameter to be passed by a pointer instead of being passed by value. Callers consume much less //! code space when passing a pointer compared to passing structs by value. //! @see window_set_window_handlers_by_value void window_set_window_handlers(Window *window, const WindowHandlers *handlers); //! Sets the window handlers of the window. //! These handlers get called e.g. when the user enters or leaves the window. //! @param window The window for which to set the window handlers //! @param handlers The handlers for the specified window //! @see \ref WindowHandlers void window_set_window_handlers_by_value(Window *window, WindowHandlers handlers); //! Sets a pointer to developer-supplied data that the window uses, to //! provide a means to access the data at later times in one of the window event handlers. //! @see window_get_user_data //! @param window The window for which to set the user data //! @param data A pointer to user data. void window_set_user_data(Window *window, void *data); //! Gets the pointer to developer-supplied data that was previously //! set using window_set_user_data(). //! @see window_set_user_data //! @param window The window for which to get the user data void* window_get_user_data(const Window *window); //! Gets the root Layer of the window. //! The root layer is the layer at the bottom of the layer hierarchy for this window. //! It is the window's "canvas" if you will. By default, the root layer only draws //! a solid fill with the window's background color. //! @param window The window for which to get the root layer //! @return The window's root layer struct Layer* window_get_root_layer(const Window *window); //! Sets the background color of the window, which is drawn automatically by the //! root layer of the window. //! @param window The window for which to set the background color //! @param background_color The new background color //! @see \ref window_get_root_layer() void window_set_background_color(Window *window, GColor background_color); void window_set_background_color_2bit(Window *window, GColor2 background_color); //! Sets whether or not the window is fullscreen, consequently hiding the sytem status bar. //! @note This needs to be called before pushing a window to the window stack. //! @param window The window for which to set its full-screen property //! @param enabled True to make the window full-screen or false to leave space for the system status bar. //! @see \ref window_get_fullscreen() void window_set_fullscreen(Window *window, bool enabled); //! Gets whether the window is full-screen, consequently hiding the sytem status bar. //! @param window The window for which to get its full-screen property //! @return True if the window is marked as fullscreen, false if it is not marked as fullscreen. bool window_get_fullscreen(const Window *window); //! Assigns an icon (max. 16x16 pixels) that can be displayed in the system status bar. //! When no icon is assigned, the icon of the previous window on the window stack is used. //! @note This needs to be called before pushing a window to the window stack. //! @param window The window for which to set the status bar icon //! @param icon The new status bar icon void window_set_status_bar_icon(Window *window, const GBitmap *icon); //! @internal //! Internal window layer update proc to be called in window subclass layer update procs void window_do_layer_update_proc(Layer *window, GContext* ctx); //! @internal //! This function gets called by the default render event handler. //! When implementing a custom render event handler, call this function //! to render the window into the context that gets passed in. //! @see PebbleAppRenderEventHandler //! @param window The window to render void window_render(Window *window, GContext *ctx); //! @internal //! Returns true if the window is currently on top of the window stack, thus on screen. //! @param window The window for which to set the `on_screen` boolean bool window_is_on_screen(Window *window); //! Gets whether the window has been loaded. //! If a window is loaded, its `.load` handler has been called (and the `.unload` handler //! has not been called since). //! @return true if the window is currently loaded or false if not. //! @param window The window to query its loaded status //! @see \ref WindowHandlers bool window_is_loaded(Window *window) ; //! @internal //! Sets whether a window is transparent. Transparent windows that are at the top of their stack //! allow the next visible window stack beneath to show through transparent areas. //! @note This currently has no affect on App windows. void window_set_transparent(Window *window, bool transparent); //! @internal //! @return true if the window is transparent, otherwise false bool window_is_transparent(Window *window); //! @internal //! Sets whether a window is focusable (e.g. can receive button events). Windows that are not //! focusable that are at the top of their stack allow the next window stack beneath to receive //! focus instead. //! @note This is not recommended for use on App windows as it results in undefined behavior. void window_set_focusable(Window *window, bool focusable); //! @internal //! @return true if the window is focusable, otherwise false bool window_is_focusable(Window *window); //! @internal //! @return A name used to identify the window. If RELEASE is defined will just return "?" //! @param window The window for which to get the debug name const char* window_get_debug_name(Window *window); //! @internal void window_call_click_config_provider(Window *window, void *context); //! Attach a recognizer to the window //! @param window \ref Window to which to attach the \ref Recognizer //! @param recognizer \ref Recognizer to attach void window_attach_recognizer(Window *window, Recognizer *recognizer); //! Detach a recognizer from the window //! @param window \ref Window from which to detach the \ref Recognizer //! @param recognizer \ref Recognizer to detach void window_detach_recognizer(Window *window, Recognizer *recognizer); //! Get the recognizers attached to a window //! @param window \ref Window from which to get recognizers //! @return recognizer list RecognizerList *window_get_recognizer_list(Window *window); //! Get the recognizer manager that manages recognizers attached to this window and all layers //! attached to the window RecognizerManager *window_get_recognizer_manager(Window *window); //! @} // end addtogroup Window //! @} // end addtogroup UI