blob: 0ac69b3963ee79d9b2c4c8c4aef700798ca3473b [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_LIB_UI_BASE_VIEW_BASE_VIEW_H_
#define SRC_LIB_UI_BASE_VIEW_BASE_VIEW_H_
#include <fuchsia/ui/gfx/cpp/fidl.h>
#include <fuchsia/ui/input/cpp/fidl.h>
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/ui/scenic/cpp/resources.h>
#include <lib/ui/scenic/cpp/session.h>
#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include "src/lib/ui/base_view/embedded_view_utils.h"
#include "src/lib/ui/base_view/math.h"
namespace scenic {
// Parameters for creating a BaseView.
struct ViewContext {
scenic::SessionPtrAndListenerRequest session_and_listener_request;
fuchsia::ui::views::ViewToken view_token;
std::optional<ViewRefPair> view_ref_pair;
sys::ComponentContext* component_context;
bool enable_ime = false;
};
// Abstract base implementation of a view for simple applications.
// Subclasses must handle layout and provide content for the scene by
// overriding the virtual methods defined in this class.
//
// It is not necessary to use this class to implement all Views.
// This class is merely intended to make the simple apps easier to write.
class BaseView : private fuchsia::ui::scenic::SessionListener,
private fuchsia::ui::input::InputMethodEditorClient {
public:
using PresentCallback = fit::function<void(const fuchsia::images::PresentationInfo& info)>;
// Subclasses are typically created by ViewProviderService::CreateView(),
// which provides the necessary args to pass down to this base class.
BaseView(ViewContext context, const std::string& debug_name);
BaseView(const BaseView&) = delete;
// |root_node| is the node directly under our View; i.e. it's the top-most
// node within the tree under our View. Use it to attach any resources for
// your UI.
scenic::EntityNode& root_node() { return root_node_; }
Session* session() { return &session_; }
sys::ComponentContext* component_context() { return component_context_; }
fuchsia::ui::gfx::ViewProperties view_properties() const { return view_properties_; }
// Returns true if the view has a non-empty size in logical pixels.
bool has_logical_size() const {
auto& sz = logical_size();
return sz.x > 0.f && sz.y > 0.f && sz.z > 0.f;
}
// Gets the size of the view in logical pixels.
// This value is zero until the view receives a layout from its parent.
const fuchsia::ui::gfx::vec3& logical_size() const { return logical_size_; }
// Returns true if the view has a non-empty size in physical pixels.
bool has_physical_size() const {
auto& sz = physical_size();
return sz.x > 0.f && sz.y > 0.f && sz.z > 0.f;
}
// Gets the size of the view in physical pixels.
// This value is zero until the view receives a layout from its parent
// and metrics from its session.
const fuchsia::ui::gfx::vec3& physical_size() const { return physical_size_; }
// Returns true if the view has received metrics from its session.
bool has_metrics() const {
return metrics_.scale_x > 0.f && metrics_.scale_y > 0.f && metrics_.scale_z > 0.f;
}
// Gets the view's metrics.
// This value is zero until the view receives metrics from its session.
const fuchsia::ui::gfx::Metrics& metrics() const { return metrics_; }
// Sets a callback which is invoked when the view's owner releases the
// view causing the view manager to unregister it.
//
// This should be used to implement cleanup policies to release resources
// associated with the view (including the object itself).
void SetReleaseHandler(fit::function<void(zx_status_t)> callback);
// Invalidates the scene, causing |OnSceneInvalidated()| to be invoked
// during the next frame. When the Present() callback corresponding to this
// invalidate is invoked, the optional |present_callback| will also be invoked.
void InvalidateScene(PresentCallback present_callback = nullptr);
// Called when it's time for the view to update its scene contents due to
// invalidation. The new contents are presented once this function returns.
//
// The default implementation does nothing.
virtual void OnSceneInvalidated(fuchsia::images::PresentationInfo presentation_info) {}
// Called when the view's properties have changed.
//
// The subclass should compare the old and new properties and make note of
// whether these property changes will affect the layout or content of
// the view then update accordingly.
//
// The default implementation does nothing.
virtual void OnPropertiesChanged(fuchsia::ui::gfx::ViewProperties old_properties) {}
// Called when the view's metrics have changed.
//
// The subclass should compare the old and new metrics and make note of
// whether this change will affect the layout or content of the view then
// update accordingly.
//
// The default implementation does nothing.
virtual void OnMetricsChanged(fuchsia::ui::gfx::Metrics old_metrics){};
// Called to handle an input event.
//
// The default implementation does nothing.
virtual void OnInputEvent(fuchsia::ui::input::InputEvent event) {}
// Called when a command sent by the client was not handled by Scenic.
//
// The default implementation does nothing.
virtual void OnUnhandledCommand(fuchsia::ui::scenic::Command unhandled) {}
// Called when an event that is not handled directly by BaseView is received.
// For example, BaseView handles fuchsia::ui::gfx::ViewPropertiesChangedEvent,
// and notifies the subclass via OnPropertiesChanged(); not all events are
// handled in this way.
//
// The default implementation does nothing.
virtual void OnScenicEvent(fuchsia::ui::scenic::Event) {}
protected:
// An alternative way to update the scene. Provide a faster way to cause a
// present in comparison to InvalidateScene(). Caller should update the
// scene contents before calling this method.
void PresentScene();
private:
// |scenic::SessionListener|
//
// Iterates over the received events and either handles them in a sensible way
// (e.g. fuchsia::ui::gfx::ViewPropertiesChangedEvent is handled by invoking
// the virtual method OnPropertiesChanged()), or delegates handling to the
// subclass via the single-event version of OnEvent() above.
//
// Subclasses should not override this.
void OnScenicEvent(std::vector<fuchsia::ui::scenic::Event> events) override;
// |fuchsia::ui::input::InputMethodEditorClient|
void DidUpdateState(fuchsia::ui::input::TextInputState state,
std::unique_ptr<fuchsia::ui::input::InputEvent> event) override;
// |fuchsia::ui::input::InputMethodEditorClient|
void OnAction(fuchsia::ui::input::InputMethodAction action) override;
void PresentScene(zx_time_t presentation_time);
// Handles focus event when IME is enabled. This event is used to activate
// or deactivate the IME client.
bool OnHandleFocusEvent(const fuchsia::ui::input::FocusEvent& focus);
// Gets a new input method editor from the IME manager.
void ActivateIme();
// Detaches the input method editor connection, ending the edit session and
// closing the onscreen keyboard.
void DeactivateIme();
sys::ComponentContext* const component_context_;
fidl::Binding<fuchsia::ui::scenic::SessionListener> listener_binding_;
Session session_;
std::optional<scenic::View> view_;
scenic::EntityNode root_node_;
fidl::Binding<fuchsia::ui::input::InputMethodEditorClient> ime_client_;
fuchsia::ui::input::InputMethodEditorPtr ime_;
fuchsia::ui::input::ImeServicePtr ime_manager_;
fuchsia::ui::gfx::vec3 logical_size_;
fuchsia::ui::gfx::vec3 physical_size_;
fuchsia::ui::gfx::ViewProperties view_properties_;
fuchsia::ui::gfx::Metrics metrics_;
zx_time_t last_presentation_time_ = 0;
size_t session_present_count_ = 0;
bool invalidate_pending_ = false;
std::vector<PresentCallback> callbacks_for_next_present_;
bool present_pending_ = false;
bool enable_ime_ = false;
};
} // namespace scenic
#endif // SRC_LIB_UI_BASE_VIEW_BASE_VIEW_H_