Program Listing for File Widget.h

Program Listing for File Widget.h#

Return to documentation for file (include/Karana/WebUI/Widget.h)

/*
 * Copyright (c) 2024-2026 Karana Dynamics Pty Ltd. All rights reserved.
 *
 * NOTICE TO USER:
 *
 * This source code and/or documentation (the "Licensed Materials") is
 * the confidential and proprietary information of Karana Dynamics Inc.
 * Use of these Licensed Materials is governed by the terms and conditions
 * of a separate software license agreement between Karana Dynamics and the
 * Licensee ("License Agreement"). Unless expressly permitted under that
 * agreement, any reproduction, modification, distribution, or disclosure
 * of the Licensed Materials, in whole or in part, to any third party
 * without the prior written consent of Karana Dynamics is strictly prohibited.
 *
 * THE LICENSED MATERIALS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
 * KARANA DYNAMICS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, AND
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * IN NO EVENT SHALL KARANA DYNAMICS BE LIABLE FOR ANY DAMAGES WHATSOEVER,
 * INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS, DATA, OR USE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, WHETHER IN CONTRACT, TORT,
 * OR OTHERWISE ARISING OUT OF OR IN CONNECTION WITH THE LICENSED MATERIALS.
 *
 * U.S. Government End Users: The Licensed Materials are a "commercial item"
 * as defined at 48 C.F.R. 2.101, and are provided to the U.S. Government
 * only as a commercial end item under the terms of this license.
 *
 * Any use of the Licensed Materials in individual or commercial software must
 * include, in the user documentation and internal source code comments,
 * this Notice, Disclaimer, and U.S. Government Use Provision.
 */

#pragma once

#include "Karana/KCore/SharedPointer.h"
#include "Karana/WebUI/Router.h"
#include "Karana/WebUI/State.h"
#include <map>

namespace Karana::WebUI {
    using StateMap = std::map<std::string, Karana::Core::ks_ptr<State>>;
    using StyleMap = std::unordered_map<std::string, std::string>;

    /**
     * @class Widget
     *
     * Note: any derived class that could be instantiated
     * MUST invoke _clearCallbacks in its destructor.
     *
     * @brief Base class for UI elements
     */
    class Widget {
      public:
        /**
         * @brief Widget constructor
         * @param router Provides a connection to the frontend
         * @param esm The esm bundle that creates a frontend Widget
         * @param css Optional css to attach to the document
         * @param states State instances used by the widget
         * @param style Style attributes for the widget's root div, using CSSOM names (use
         * camelCase)
         * @param init_msg Passed to widget frontend's initialize method
         */
        Widget(Router &router,
               const ContentSource &esm,
               const ContentSource &css = {},
               const StateMap &states = {},
               const StyleMap &style = {},
               std::string_view init_msg = {});

        /**
         * @brief Widget destructor
         */
        virtual ~Widget();

        /**
         * @brief Get a handle to the widget's channel
         * @return The channel
         */
        const Karana::Core::ks_ptr<Channel> &channel() const;

        /**
         * @brief Get the id of the widget's root div in the DOM
         * @return The id
         */
        std::string_view domId() const;

        /**
         * @brief Get a state instance
         *
         * Throws an error if the name isn't known.
         *
         * @param name The name assigned to the state by this widget
         * @return The non-null state
         */
        const Karana::Core::ks_ptr<State> &state(std::string_view name) const;

        /**
         * @brief Set whether the widget should be rendered
         * @param visible The visibility flag
         */
        void setVisible(bool visible);

        /**
         * @brief Add the widget to the document's root div.
         *
         * This should be called on the widget which acts as the root
         * container for all other widgets in an application.
         */
        void addToDomRoot();

      protected:
        /**
         * @brief Send a message to the frontend.
         * @param message The message to send.
         * @param client_id The client to message.
         */
        void _sendMessage(std::string_view message, int client_id);

        /**
         * @brief Send a message to all clients.
         * @param message The message to send.
         */
        void _broadcastMessage(std::string_view message);

        /**
         * @brief Called upon a client connecting.
         *
         * This can be overridden to implement custom behavior.
         *
         * @param client_id Unique id for the client.
         */
        virtual void _onConnect([[maybe_unused]] int client_id) {}

        /**
         * @brief Called upon a message from a client.
         *
         * This can be overridden to implement custom behavior.
         *
         * @param message The message from the client
         * @param client_id Unique id for the client
         */
        virtual void _onMessage([[maybe_unused]] std::string_view message,
                                [[maybe_unused]] int client_id) {}

        /**
         * @brief Called upon a client disconnecting.
         *
         * This can be overridden to implement custom behavior.
         *
         * @param client_id Unique id for the client.
         */
        virtual void _onDisconnect([[maybe_unused]] int client_id) {}

        /**
         * @brief Thread-safely clear any event callbacks
         *
         * This MUST be called in the destructor of any
         * subclass that may be instantiated.
         */
        void _clearCallbacks();

      private:
        std::unique_ptr<struct WidgetImpl> _impl;
    };

} // namespace Karana::WebUI