mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-12-16 01:48:56 +08:00
Start the tree-aware selection.
This commit is contained in:
@@ -64,6 +64,30 @@ class HBox : public Node {
|
||||
x = box.x_max + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Selection(Box selection, std::vector<Box>* selected) override {
|
||||
// If this Node box_ doesn't intersect with the selection, then no
|
||||
// selection.
|
||||
if (Box::Intersection(selection, box_).IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool xmin_satured =
|
||||
selection.y_min < box_.y_min || selection.x_min < box_.x_min;
|
||||
const bool xmax_satured =
|
||||
selection.y_max > box_.y_max || selection.x_max > box_.x_max;
|
||||
|
||||
if (xmin_satured) {
|
||||
selection.x_min = box_.x_min;
|
||||
}
|
||||
if (xmax_satured) {
|
||||
selection.x_max = box_.x_max;
|
||||
}
|
||||
|
||||
for (auto& child : children_) {
|
||||
child->Selection(selection, selected);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <iostream>
|
||||
// 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.
|
||||
@@ -27,6 +28,20 @@ void Node::SetBox(Box box) {
|
||||
box_ = box;
|
||||
}
|
||||
|
||||
/// @brief Compute the selection of an element.
|
||||
/// @ingroup dom
|
||||
void Node::Selection(Box selection, std::vector<Box>* selected) {
|
||||
// If this Node box_ doesn't intersect with the selection, then no selection.
|
||||
if (Box::Intersection(selection, box_).IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// By default we defer the selection to the children.
|
||||
for (auto& child : children_) {
|
||||
child->Selection(selection, selected);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Display an element on a ftxui::Screen.
|
||||
/// @ingroup dom
|
||||
void Node::Render(Screen& screen) {
|
||||
@@ -45,12 +60,16 @@ void Node::Check(Status* status) {
|
||||
/// @brief Display an element on a ftxui::Screen.
|
||||
/// @ingroup dom
|
||||
void Render(Screen& screen, const Element& element) {
|
||||
Render(screen, element.get());
|
||||
Render(screen, element.get(), Box{0, 0, -1, -1});
|
||||
}
|
||||
|
||||
/// @brief Display an element on a ftxui::Screen.
|
||||
/// @ingroup dom
|
||||
void Render(Screen& screen, Node* node) {
|
||||
Render(screen, node, Box{0, 0, -1, -1});
|
||||
}
|
||||
|
||||
void Render(Screen& screen, Node* node, Box selection) {
|
||||
Box box;
|
||||
box.x_min = 0;
|
||||
box.y_min = 0;
|
||||
@@ -73,11 +92,15 @@ void Render(Screen& screen, Node* node) {
|
||||
node->Check(&status);
|
||||
}
|
||||
|
||||
// Step 3: Draw the element.
|
||||
// Step 3: Selection
|
||||
std::vector<Box> selected;
|
||||
node->Selection(selection, &selected);
|
||||
|
||||
// Step 4: Draw the element.
|
||||
screen.stencil = box;
|
||||
node->Render(screen);
|
||||
|
||||
// Step 4: Apply shaders
|
||||
// Step 5: Apply shaders
|
||||
screen.ApplyShader();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,29 @@ class Text : public Node {
|
||||
requirement_.min_y = 1;
|
||||
}
|
||||
|
||||
void Selection(Box selection, std::vector<Box>* selected) override {
|
||||
if (Box::Intersection(selection, box_).IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool xmin_satured =
|
||||
selection.y_min < box_.y_min || selection.x_min < box_.x_min;
|
||||
const bool xmax_satured =
|
||||
selection.y_max > box_.y_max || selection.x_max > box_.x_max;
|
||||
|
||||
selection_start_ = xmin_satured ? box_.x_min : selection.x_min;
|
||||
selection_end_ = xmax_satured ? box_.x_max : selection.x_max;
|
||||
|
||||
has_selection = true;
|
||||
|
||||
Box out;
|
||||
out.x_min = selection_start_;
|
||||
out.x_max = selection_end_;
|
||||
out.y_min = box_.y_min;
|
||||
out.y_max = box_.y_max;
|
||||
selected->push_back(out);
|
||||
}
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
int x = box_.x_min;
|
||||
const int y = box_.y_min;
|
||||
@@ -35,55 +58,33 @@ class Text : public Node {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the selection start point
|
||||
int selection_start_x = !screen.selection_region.isXInverted ? screen.selection_region.x_min : screen.selection_region.x_max;
|
||||
int selection_start_y = !screen.selection_region.isYInverted ? screen.selection_region.y_min : screen.selection_region.y_max;
|
||||
bool selectedWidget = false;
|
||||
|
||||
if(box_.Contain(selection_start_x, selection_start_y))
|
||||
{
|
||||
selectedWidget = true;
|
||||
}
|
||||
|
||||
for (const auto& cell : Utf8ToGlyphs(text_)) {
|
||||
if (x > box_.x_max) {
|
||||
return;
|
||||
break;
|
||||
}
|
||||
if (cell == "\n") {
|
||||
continue;
|
||||
}
|
||||
Pixel ¤tPixel = screen.PixelAt(x, y);
|
||||
currentPixel.character = cell;
|
||||
|
||||
if((selectedWidget == true) && (currentPixel.selectable == true))
|
||||
{
|
||||
if(screen.selection_region.Contain(x, y)) {
|
||||
currentPixel.inverted ^= true;
|
||||
screen.selection_text += currentPixel.character;
|
||||
}
|
||||
else if((x >= screen.selection_region.x_min) && (x >= screen.selection_region.x_max) &&
|
||||
(y >= screen.selection_region.y_min) && (y < screen.selection_region.y_max))
|
||||
{
|
||||
// Wrap around selection on the right
|
||||
currentPixel.inverted ^= true;
|
||||
screen.selection_text += currentPixel.character;
|
||||
}
|
||||
else if((x <= screen.selection_region.x_min) && (x <= screen.selection_region.x_max) &&
|
||||
(y > screen.selection_region.y_min) && (y <= screen.selection_region.y_max))
|
||||
{
|
||||
// Wrap around selection on the left
|
||||
currentPixel.inverted ^= true;
|
||||
screen.selection_text += currentPixel.character;
|
||||
}
|
||||
|
||||
}
|
||||
screen.PixelAt(x, y).character = cell;
|
||||
|
||||
++x;
|
||||
}
|
||||
|
||||
if (!has_selection) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Invert the selection
|
||||
for(int x = selection_start_; x <= selection_end_; x++) {
|
||||
screen.PixelAt(x, y).inverted = true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::string text_;
|
||||
bool has_selection = false;
|
||||
int selection_start_ = 0;
|
||||
int selection_end_ = 10;
|
||||
};
|
||||
|
||||
class VText : public Node {
|
||||
|
||||
@@ -64,6 +64,29 @@ class VBox : public Node {
|
||||
y = box.y_max + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Selection(Box selection, std::vector<Box>* selected) override {
|
||||
// If this Node box_ doesn't intersect with the selection, then no
|
||||
// selection.
|
||||
if (Box::Intersection(selection, box_).IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool ymin_satured =
|
||||
selection.x_min < box_.x_min || selection.y_min < box_.y_min;
|
||||
const bool ymax_satured =
|
||||
selection.x_max > box_.x_max || selection.y_max > box_.y_max;
|
||||
if (ymin_satured) {
|
||||
selection.y_min = box_.y_min;
|
||||
}
|
||||
if (ymax_satured) {
|
||||
selection.y_max = box_.y_max;
|
||||
}
|
||||
|
||||
for (auto& child : children_) {
|
||||
child->Selection(selection, selected);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
||||
Reference in New Issue
Block a user