FTXUI/src/ftxui/component/component.cpp

154 lines
4.5 KiB
C++
Raw Normal View History

2021-05-15 04:00:49 +08:00
#include <algorithm> // for find_if, max
#include <iterator> // for begin, end
#include <utility> // for move
2020-03-23 05:32:44 +08:00
2021-05-10 02:32:27 +08:00
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface
#include "ftxui/component/component.hpp"
#include "ftxui/component/component_base.hpp" // for ComponentBase, Component
#include "ftxui/component/event.hpp" // for Event
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#include "ftxui/dom/elements.hpp" // for text, Element
2021-05-02 02:40:35 +08:00
namespace ftxui {
2021-05-02 02:40:35 +08:00
namespace {
class CaptureMouseImpl : public CapturedMouseInterface {
public:
~CaptureMouseImpl() override {}
};
2021-05-10 02:32:27 +08:00
} // namespace
2021-05-02 02:40:35 +08:00
2021-05-10 02:32:27 +08:00
ComponentBase::~ComponentBase() {
while (children_.size() != 0)
children_.back()->Detach();
2019-01-13 01:24:46 +08:00
}
2021-05-10 02:32:27 +08:00
/// @brief Return the parent ComponentBase, or nul if any.
2020-08-16 08:24:50 +08:00
/// @see Attach
/// @see Detach
2020-09-06 19:46:56 +08:00
/// @see Parent
2020-08-16 08:24:50 +08:00
/// @ingroup component
2021-05-10 02:32:27 +08:00
ComponentBase* ComponentBase::Parent() {
2020-08-16 08:24:50 +08:00
return parent_;
}
/// @brief Add a children.
/// @@param child The child to be attached.
/// @ingroup component
2021-05-10 02:32:27 +08:00
void ComponentBase::Add(Component child) {
child->Detach();
child->parent_ = this;
children_.push_back(std::move(child));
}
2020-08-16 08:24:50 +08:00
/// @brief Draw the component.
/// Build a ftxui::Element to be drawn on the ftxi::Screen representing this
2021-05-10 02:32:27 +08:00
/// ftxui::ComponentBase.
2020-08-16 08:24:50 +08:00
/// @ingroup component
2021-05-10 02:32:27 +08:00
Element ComponentBase::Render() {
2020-08-16 08:24:50 +08:00
if (children_.size() == 1)
return children_.front()->Render();
return text(L"Not implemented component");
}
2020-08-16 08:24:50 +08:00
/// @brief Called in response to an event.
/// @param event The event.
/// @return True when the event has been handled.
/// The default implementation called OnEvent on every child until one return
/// true. If none returns true, return false.
/// @ingroup component
2021-05-10 02:32:27 +08:00
bool ComponentBase::OnEvent(Event event) {
for (Component& child : children_) {
2019-01-13 01:24:46 +08:00
if (child->OnEvent(event))
return true;
}
return false;
}
2020-08-16 08:24:50 +08:00
/// @brief Return the currently Active child.
/// @return the currently Active child.
/// @ingroup component
2021-05-10 02:32:27 +08:00
Component ComponentBase::ActiveChild() {
2019-01-13 01:24:46 +08:00
return children_.empty() ? nullptr : children_.front();
}
/// @brief Returns if the element if the currently active child of its parent.
/// @ingroup component
2021-05-10 02:32:27 +08:00
bool ComponentBase::Active() {
return !parent_ || parent_->ActiveChild().get() == this;
}
2020-08-16 08:24:50 +08:00
/// @brief Returns if the elements if focused by the user.
2021-05-10 02:32:27 +08:00
/// True when the ComponentBase is focused by the user. An element is Focused
/// when it is with all its ancestors the ActiveChild() of their parents.
/// @ingroup component
2021-05-10 02:32:27 +08:00
bool ComponentBase::Focused() {
ComponentBase* current = this;
2020-03-23 05:32:44 +08:00
for (;;) {
2021-05-10 02:32:27 +08:00
ComponentBase* parent = current->parent_;
2019-01-13 01:24:46 +08:00
if (!parent)
return true;
2021-05-10 02:32:27 +08:00
if (parent->ActiveChild().get() != current)
2019-01-13 01:24:46 +08:00
return false;
current = parent;
}
}
/// @brief Make the |child| to be the "active" one.
2021-07-10 20:23:46 +08:00
/// @param child the child to become active.
/// @ingroup component
2021-05-10 02:32:27 +08:00
void ComponentBase::SetActiveChild(ComponentBase*) {}
/// @brief Make the |child| to be the "active" one.
2021-07-10 20:23:46 +08:00
/// @param child the child to become active.
2021-05-10 02:32:27 +08:00
/// @ingroup component
void ComponentBase::SetActiveChild(Component child) {
SetActiveChild(child.get());
}
/// @brief Configure all the ancestors to give focus to this component.
/// @ingroup component
2021-05-10 02:32:27 +08:00
void ComponentBase::TakeFocus() {
ComponentBase* child = this;
ComponentBase* parent = parent_;
while (parent) {
parent->SetActiveChild(child);
child = parent;
parent = parent->parent_;
}
}
2021-05-02 02:40:35 +08:00
/// @brief Take the CapturedMouse if available. There is only one component of
/// them. It represents a component taking priority over others.
2021-07-10 20:23:46 +08:00
/// @param event
2021-05-02 02:40:35 +08:00
/// @ingroup component
2021-05-10 02:32:27 +08:00
CapturedMouse ComponentBase::CaptureMouse(const Event& event) {
2021-05-02 02:40:35 +08:00
if (!event.screen_)
return std::make_unique<CaptureMouseImpl>();
return event.screen_->CaptureMouse();
}
2020-08-16 08:24:50 +08:00
/// @brief Detach this children from its parent.
/// @see Attach
/// @see Detach
2020-09-06 19:46:56 +08:00
/// @see Parent
2020-08-16 08:24:50 +08:00
/// @ingroup component
2021-05-10 02:32:27 +08:00
void ComponentBase::Detach() {
2020-08-16 08:24:50 +08:00
if (!parent_)
return;
2021-05-10 02:32:27 +08:00
auto it = std::find_if(std::begin(parent_->children_), //
std::end(parent_->children_), //
[this](const Component& that) { //
return this == that.get();
});
2020-08-16 08:24:50 +08:00
parent_->children_.erase(it);
parent_ = nullptr;
2020-08-16 08:24:50 +08:00
}
} // namespace ftxui
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.