From f3c2e5942e65e02604fb3f44c5752c809986bdc9 Mon Sep 17 00:00:00 2001 From: djowel Date: Sat, 22 Jun 2024 10:47:51 +0800 Subject: [PATCH] port documentation --- examples/sync_scrollbars/main.cpp | 2 +- lib/include/elements/element/port.hpp | 486 ++++++++++++++++++++------ lib/src/element/port.cpp | 109 +++++- 3 files changed, 477 insertions(+), 120 deletions(-) diff --git a/examples/sync_scrollbars/main.cpp b/examples/sync_scrollbars/main.cpp index cc7efe44..a1cc1693 100644 --- a/examples/sync_scrollbars/main.cpp +++ b/examples/sync_scrollbars/main.cpp @@ -45,7 +45,7 @@ int main(int argc, char* argv[]) // Second scrollers will follow first scroller position scr.on_scroll = [&](point p) { - scr2.set_position(p); + scr2.set_alignment(p); view_.layout(); view_.refresh(); }; diff --git a/lib/include/elements/element/port.hpp b/lib/include/elements/element/port.hpp index 7973e50c..4b355fab 100644 --- a/lib/include/elements/element/port.hpp +++ b/lib/include/elements/element/port.hpp @@ -40,36 +40,19 @@ namespace cycfi::elements virtual void valign(double val) = 0; }; - // Utility to find the bounds established by the innermost port given a - // child context. If there is none, returns ctx.view_bounds() + rect get_port_bounds(context const& ctx); /** - * @brief - * Finds the bounds established by the innermost port. - * - * This utility function searches for the bounds of the innermost port. - * If no port is found, the function returns the view's bounds. - * - * @param ctx - * The context of the child element for which the port bounds are being - * determined. This context carries information about the current state - * of the UI, including any enclosing ports. + * @class port_element * - * @return - * The rectangular bounds defined by the innermost port affecting the - * given context, or the view bounds if no such port exists. + * @brief + * A port element with alignment capabilities, extending `port_base`. + * This class models supports horizontal and vertical alignment. */ - rect get_port_bounds(context const& ctx); - class port_element : public port_base { public: - port_element() - : _halign(0.0) - , _valign(0.0) - {} - - ~port_element() {} + port_element(); view_limits limits(basic_context const& ctx) const override; void prepare_subject(context& ctx) override; @@ -87,47 +70,30 @@ namespace cycfi::elements template inline proxy, port_element> - port(Subject&& subject) - { - return {std::forward(subject)}; - } - - inline double port_element::halign() const - { - return _halign; - } - - inline void port_element::halign(double val) - { - _halign = val; - } - - inline double port_element::valign() const - { - return _valign; - } - - inline void port_element::valign(double val) - { - _valign = val; - } + port(Subject&& subject); + /** + * @class vport_element + * + * @brief + * A vertical port element that extends `port_base`, specifically + * designed for vertical alignment within a port. + * + * This class represents a vertical viewport or window over a larger + * area, allowing content to be aligned vertically. + */ class vport_element : public port_base { public: - vport_element() - : _valign(0.0) - {} - - ~vport_element() {} + vport_element(); view_limits limits(basic_context const& ctx) const override; void prepare_subject(context& ctx) override; - double halign() const override { return 0; } - void halign(double /*val*/) override {} - double valign() const override { return _valign; } - void valign(double val) override { _valign = val; } + double halign() const override { return 0; } + void halign(double /*val*/) override {} + double valign() const override { return _valign; } + void valign(double val) override { _valign = val; } private: @@ -136,19 +102,22 @@ namespace cycfi::elements template inline proxy, vport_element> - vport(Subject&& subject) - { - return {std::forward(subject)}; - } + vport(Subject&& subject); + /** + * @class hport_element + * + * @brief + * A horizontal port element that extends `port_base`, specifically + * designed for horizontal alignment within a port. + * + * This class represents a horizontal viewport or window over a larger + * area, allowing content to be aligned horizontally. + */ class hport_element : public port_base { public: - hport_element() - : _halign(0.0) - {} - - ~hport_element() {} + hport_element(); view_limits limits(basic_context const& ctx) const override; void prepare_subject(context& ctx) override; @@ -165,44 +134,49 @@ namespace cycfi::elements template inline proxy, hport_element> - hport(Subject&& subject) - { - return {std::forward(subject)}; - } + hport(Subject&& subject); - //////////////////////////////////////////////////////////////////////////// - // Scrollers - //////////////////////////////////////////////////////////////////////////// - - // scrollable: Mixin class for a element that is scrollable - // scroll the rectangle, r into view + /** + * @class scrollable + * + * @brief + * Mixin class for an element that is scrollable. + * + * Provides functionality to scroll a given rectangle into view within + * the context of a scrollable area. + */ class scrollable { public: - virtual ~scrollable() = default; - - struct scrollable_context - { - context const* context_ptr; - scrollable* scrollable_ptr; - - // scroll the rectangle, r into view - bool scroll_into_view(rect r_) - { - if (scrollable_ptr && context_ptr) - { - rect r = r_; - return scrollable_ptr->scroll_into_view(*context_ptr, r); - } - return false; - } - }; + struct scrollable_context; + virtual ~scrollable() = default; virtual bool scroll_into_view(context const& ctx, rect r) = 0; static scrollable_context find(context const& ctx); }; + /** + * @struct scrollable::scrollable_context + * + * @brief + * The context within which a scrollable element operates. + */ + struct scrollable::scrollable_context + { + context const* context_ptr; + scrollable* scrollable_ptr; + + bool scroll_into_view(rect r_); + }; + + /** + * @enum ScrollbarFlags + * @brief Flags to control the visibility and behavior of scrollbars. + * @var no_scrollbars: Hides all scrollbars. + * @var no_hscroll: Disables horizontal scrolling. + * @var no_vscroll: Disables vertical scrolling. + */ enum { no_scrollbars = 1, @@ -210,16 +184,25 @@ namespace cycfi::elements no_vscroll = 1 << 2 }; - // Base proxy class for views that are scrollable + /** + * @class scroller_base + * + * @brief + * Base proxy class for views that are scrollable. + * + * Inherits from `port_element` and `scrollable` to provide a + * foundation for elements that require scrollable functionality. + * + * The `scroller_base` class also manages the visibility and behavior + * of horizontal and vertical scrollbars based on the traits specified + * upon construction. It supports dynamic adjustment of content + * positioning within the scrollable area. + */ class scroller_base : public port_element, public scrollable { public: - scroller_base(int traits = 0) - : _tracking(none) - , _traits(traits) - {} - ~scroller_base() {} + explicit scroller_base(int traits = 0); view_limits limits(basic_context const& ctx) const override; void prepare_subject(context& ctx) override; @@ -235,14 +218,13 @@ namespace cycfi::elements bool key(context const& ctx, key_info k) override; std::function on_scroll = [](point){}; - void set_position(point p); - struct scrollbar_info - { - double pos; - float extent; - rect bounds; - }; + void set_alignment(point p); + + [[deprecated("use set_alignment(p) instead")]] + void set_position(point p) { set_alignment(p); } + + struct scrollbar_info; virtual void draw_scroll_bar(context const& ctx, scrollbar_info const& info, point mp); virtual rect scroll_bar_position(context const& ctx, scrollbar_info const& info); @@ -277,6 +259,252 @@ namespace cycfi::elements int _traits; }; + /** + * @struct scrollbar_info + * + * @brief + * Information about a scrollbar. + * + * @var pos + * The current position of the scrollbar represented as an alignment + * fraction from 0.0 to 1.0. + * + * @var extent + * The size of the content area. + * + * @var bounds + * The geometric bounds of the scrollbar within the scroller. This + * `rect` defines the position and size of the scrollbar. + */ + struct scroller_base::scrollbar_info + { + double pos; + float extent; + rect bounds; + }; + + //////////////////////////////////////////////////////////////////////////// + // Inlines + //////////////////////////////////////////////////////////////////////////// + namespace inlines {} + + /** + * @brief + * Creates a proxy object that wraps a given UI element, allowing it to + * be displayed within a port. + * + * This template function wraps a UI element (`subject`) in a + * `port_element`, enabling the element to be displayed as part of a + * port. A port is a window or viewport over a larger area, and + * elements within a port can be aligned and scrolled within this area. + * + * @tparam Subject + * The type of the UI element to be wrapped. Must meet the requirements + * of the `concepts::Element` concept. + * + * @param subject + * The UI element to be wrapped in the port. + * + * @return + * A proxy object that wraps the specified UI element in a + * `port_element`. + */ + template + inline proxy, port_element> + port(Subject&& subject) + { + return {std::forward(subject)}; + } + + /** + * @brief + * Default constructor for the port_element class. + */ + inline port_element::port_element() + : _halign(0.0) + , _valign(0.0) + {} + + /** + * @brief + * Get the current horizontal alignment of the port element. + * + * @return + * The current horizontal alignment value, ranging from 0.0 to 1.0. + */ + inline double port_element::halign() const + { + return _halign; + } + + /** + * @brief + * Set the horizontal alignment of the port element. + * + * @param val + * The new horizontal alignment value, ranging from 0.0 to 1.0. + */ + inline void port_element::halign(double val) + { + _halign = val; + } + + /** + * @brief + * Get the current vertical alignment of the port element. + * + * @return + * The current vertical alignment value, ranging from 0.0 to 1.0. + */ + inline double port_element::valign() const + { + return _valign; + } + + /** + * @brief + * Set the vertical alignment of the port element. + * + * @param val + * The new vertical alignment value, ranging from 0.0 to 1.0. + */ + inline void port_element::valign(double val) + { + _valign = val; + } + + /** + * @brief + * Constructs a `vport_element`. + */ + inline vport_element::vport_element() + : _valign(0.0) + { + } + + /** + * @brief + * Creates a vertical port element that wraps a given UI element, + * allowing it to be displayed within a vertical port. + * + * This function template creates a `vport_element` that wraps the + * given UI element (`subject`), enabling the element to be displayed + * as part of a vertical port. A vertical port is a viewport that + * allows vertical scrolling and alignment within a larger area. + * + * @tparam Subject + * The type of the UI element to be wrapped. Must meet the requirements + * of the `concepts::Element` concept. + * + * @param subject + * The UI element to be wrapped in the vertical port. + * + * @return + * A proxy's subject that wraps the specified UI element in a + * `vport_element`. + */ + template + inline proxy, vport_element> + vport(Subject&& subject) + { + return {std::forward(subject)}; + } + + /** + * @brief + * Constructs an `hport_element`. + */ + inline hport_element::hport_element() + : _halign(0.0) + {} + + /** + * @brief + * Creates a horizontal port element that wraps a given UI element, + * allowing it to be displayed within a horizontal port. + * + * This function template creates a `hport_element` that wraps the + * given UI element (`subject`), enabling the element to be displayed + * as part of a horizontal port. A horizontal port is a viewport that + * allows horizontal scrolling and alignment within a larger area. + * + * @tparam Subject + * The type of the UI element to be wrapped. Must meet the requirements + * of the `concepts::Element` concept. + * + * @param subject + * The UI element to be wrapped in the horizontal port. + * + * @return + * A proxy's subject that wraps the specified UI element in a + * `hport_element`. + */ + template + inline proxy, hport_element> + hport(Subject&& subject) + { + return {std::forward(subject)}; + } + + /** + * @brief + * Attempts to scroll the rectangle, r_, into view. + * + * If both `scrollable_ptr` and `context_ptr` are valid, it calls the + * `scroll_into_view` member function of the scrollable object to + * attempt to scroll the rectangle into view. + * + * @param r_ + * The rectangle to scroll into view. + * + * @return + * True if the operation was successful, false otherwise. + */ + inline bool scrollable::scrollable_context::scroll_into_view(rect r_) + { + if (scrollable_ptr && context_ptr) + { + rect r = r_; + return scrollable_ptr->scroll_into_view(*context_ptr, r); + } + return false; + } + + /** + * @brief + * Constructor for scroller_base. + * + * @param traits + * Configuration traits for the scroller, controlling its behavior and + * appearance. + */ + inline scroller_base::scroller_base(int traits) + : _tracking(none) + , _traits(traits) + {} + + /** + * @brief + * Creates a generic scroller. + * + * Constructs a proxy object wrapping a given subject with + * scroller_base, allowing the subject to be scrolled both horizontally + * and vertically, depending on the specified traits. + * + * @tparam Subject + * The type of the subject to be wrapped. Must satisfy the + * concepts::Element concept. + * + * @param subject + * The subject to be wrapped in a scroller. + * + * @param traits + * Configuration traits for the scroller. + * + * @return + * A proxy object wrapping the subject with scroller_base + * functionality. + */ template inline proxy, scroller_base> scroller(Subject&& subject, int traits = 0) @@ -284,6 +512,29 @@ namespace cycfi::elements return {std::forward(subject), traits}; } + /** + * @brief + * Creates a vertical scroller. + * + * Constructs a proxy object wrapping a given subject with + * scroller_base, specifically for vertical scrolling by automatically + * disabling horizontal scrolling through the traits. + * + * @tparam Subject + * The type of the subject to be wrapped. Must satisfy the + * concepts::Element concept. + * + * @param subject + * The subject to be wrapped in a vertical scroller. + * + * @param traits + * Configuration traits for the scroller, with horizontal scrolling + * disabled. + * + * @return + * A proxy object wrapping the subject with vertical scroller_base + * functionality. + */ template inline proxy, scroller_base> vscroller(Subject&& subject, int traits = 0) @@ -291,6 +542,29 @@ namespace cycfi::elements return {std::forward(subject), traits | no_hscroll}; } + /** + * @brief + * Creates a horizontal scroller. + * + * Constructs a proxy object wrapping a given subject with + * scroller_base, specifically for horizontal scrolling by + * automatically disabling vertical scrolling through the traits. + * + * @tparam Subject + * The type of the subject to be wrapped. Must satisfy the + * concepts::Element concept. + * + * @param subject + * The subject to be wrapped in a horizontal scroller. + * + * @param traits + * Configuration traits for the scroller, with vertical scrolling + * disabled. + * + * @return + * A proxy object wrapping the subject with horizontal scroller_base + * functionality. + */ template inline proxy, scroller_base> hscroller(Subject&& subject, int traits = 0) diff --git a/lib/src/element/port.cpp b/lib/src/element/port.cpp index 242de45f..1d3e453e 100644 --- a/lib/src/element/port.cpp +++ b/lib/src/element/port.cpp @@ -26,6 +26,23 @@ namespace cycfi::elements proxy_base::draw(ctx); } + /** + * @brief + * Utility to find the bounds established by the innermost port given a + * child context. If there is none, returns ctx.view_bounds(). + * + * This utility function searches for the bounds of the innermost port. + * If no port is found, the function returns the view's bounds. + * + * @param ctx + * The context of the child element for which the port bounds are being + * determined. This context carries information about the current state + * of the UI, including any enclosing ports. + * + * @return + * The rectangular bounds defined by the innermost port affecting the + * given context, or the view bounds if no such port exists. + */ rect get_port_bounds(context const& ctx) { if (auto pctx = find_parent_context(ctx)) @@ -33,9 +50,6 @@ namespace cycfi::elements return ctx.view_bounds(); } - //////////////////////////////////////////////////////////////////////////// - // port_element class implementation - //////////////////////////////////////////////////////////////////////////// view_limits port_element::limits(basic_context const& ctx) const { view_limits e_limits = subject().limits(ctx); @@ -58,9 +72,6 @@ namespace cycfi::elements subject().layout(ctx); } - //////////////////////////////////////////////////////////////////////////// - // vport_element class implementation - //////////////////////////////////////////////////////////////////////////// view_limits vport_element::limits(basic_context const& ctx) const { view_limits e_limits = subject().limits(ctx); @@ -79,9 +90,6 @@ namespace cycfi::elements subject().layout(ctx); } - //////////////////////////////////////////////////////////////////////////// - // hport_element class implementation - //////////////////////////////////////////////////////////////////////////// view_limits hport_element::limits(basic_context const& ctx) const { view_limits e_limits = subject().limits(ctx); @@ -100,9 +108,29 @@ namespace cycfi::elements subject().layout(ctx); } - //////////////////////////////////////////////////////////////////////////// - // scrollable class implementation - //////////////////////////////////////////////////////////////////////////// + /** + * @brief + * Finds the nearest scrollable context in the hierarchy. + * + * This function traverses the context hierarchy starting from the + * given context (`ctx_`), searching for the nearest parent (or the + * context itself) that contains a scrollable element. It utilizes the + * `find_element` function to locate a `scrollable` instance within the + * current context's element. + * + * If a scrollable element is found, a `scrollable_context` struct is + * returned, containing pointers to both the context and the scrollable + * element. If no scrollable element is found in the hierarchy, the + * function returns a `scrollable_context` with null pointers. + * + * @param ctx_ + * The starting context for the search. + * + * @return + * A `scrollable_context` struct with pointers to the found context and + * scrollable element. If not found, both pointers in the struct will + * be null. + */ scrollable::scrollable_context scrollable::find(context const& ctx_) { auto const* ctx = &ctx_; @@ -151,6 +179,21 @@ namespace cycfi::elements } } + /** + * @brief + * Draws the scrollbar for the scroller_base. + * + * @param ctx + * The drawing context, containing the canvas and other relevant + * drawing information. + * + * @param info + * A `scrollbar_info` struct containing details about the scrollbar's + * bounds, position, and extent. + * + * @param mp + * The current mouse position. + */ void scroller_base::draw_scroll_bar(context const& ctx, scrollbar_info const& info, point mp) { theme const& thm = get_theme(); @@ -181,6 +224,25 @@ namespace cycfi::elements _tracking == ((w > h)? tracking_h : tracking_v)); } + /** + * @brief + * Calculates the position and size of the scrollbar. + * + * This function determines the position and size of the scrollbar + * within the scroller_base, based on the current scrolling information + * provided by `info`. + * + * @param ctx + * The drawing context. + * + * @param info + * A `scrollbar_info` struct containing details about the current + * scroll state, including the bounds of the scroller_base, the + * position of the scrollbar, and the total extent of the content. + * + * @return + * A `rect` representing the position and size of the scrollbar. + */ rect scroller_base::scroll_bar_position(context const& /* ctx */, scrollbar_info const& info) { float x = info.bounds.left; @@ -343,7 +405,28 @@ namespace cycfi::elements return port_element::scroll(ctx, dir, p) || redraw; } - void scroller_base::set_position(point p) + /** + * @brief + * Sets the scroll alignment of the scroller_base. + * + * This function adjusts the scroll alignment of the scroller_base + * object based on the specified point `p`, considering horizontal and + * vertical scrolling capabilities, and adjusts the scroll alignment + * accordingly. + * + * If horizontal scrolling is allowed (`allow_hscroll()` returns true), + * it sets the horizontal alignment (scroll alignment) to the + * x-coordinate of the point `p`. Similarly, if vertical scrolling is + * allowed (`allow_vscroll()` returns true), it sets the vertical + * alignment (scroll alignment) to the y-coordinate of the point `p`. + * + * Take note that alignment values are clamped to the range [0.0, 1.0]. + * + * @param p + * The point representing the new scroll alignment, where `p.x` is the + * new horizontal alignment and `p.y` is the new vertical alignment. + */ + void scroller_base::set_alignment(point p) { if (allow_hscroll()) halign(p.x);