mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2024-11-26 04:31:34 +08:00
Mouse support. Fix & verify Webassembly support.
There was some undefined behavior to be fixed in the terminal input parser. The behavior of flush seems to have change. The fix was to invert '\0' and std::flush.
This commit is contained in:
parent
0b9b6c692a
commit
a27c878a3f
@ -10,7 +10,7 @@
|
|||||||
<div class="page">
|
<div class="page">
|
||||||
<h1>FTXUI WebAssembly Example </h1>
|
<h1>FTXUI WebAssembly Example </h1>
|
||||||
<p>
|
<p>
|
||||||
<a href="https://github.com/ArthurSonzogni/FTXUI">FTXUI</a> is a single
|
<a href="https://github.com/ArthurSonzogni/FTXUI">FTXUI</a> is a simple
|
||||||
C++ library for terminal user interface.
|
C++ library for terminal user interface.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
@ -69,10 +69,8 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
const url_search_params = new URLSearchParams(window.location.search);
|
const url_search_params = new URLSearchParams(window.location.search);
|
||||||
const example_index = url_search_params.get("id") || 16;
|
const example = url_search_params.get("file") || "./dom/color_gallery.js"
|
||||||
const example = example_list[example_index];
|
const select = document.getElementById("selectExample");
|
||||||
|
|
||||||
var select = document.getElementById("selectExample");
|
|
||||||
|
|
||||||
for(var i = 0; i < example_list.length; i++) {
|
for(var i = 0; i < example_list.length; i++) {
|
||||||
var opt = example_list[i];
|
var opt = example_list[i];
|
||||||
@ -81,9 +79,10 @@
|
|||||||
el.value = opt;
|
el.value = opt;
|
||||||
select.appendChild(el);
|
select.appendChild(el);
|
||||||
}
|
}
|
||||||
select.selectedIndex = example_index;
|
select.selectedIndex = example_list.findIndex(path => path == example) || 0;
|
||||||
select.addEventListener("change", () => {
|
select.addEventListener("change", () => {
|
||||||
location.href = (location.href).split('?')[0] + "?id=" + select.selectedIndex;
|
location.href = (location.href).split('?')[0] + "?file=" +
|
||||||
|
example_list[select.selectedIndex];
|
||||||
});
|
});
|
||||||
|
|
||||||
let stdin_buffer = [];
|
let stdin_buffer = [];
|
||||||
@ -94,6 +93,7 @@
|
|||||||
stdout_buffer = [];
|
stdout_buffer = [];
|
||||||
let stdout = code => {
|
let stdout = code => {
|
||||||
if (code == 0) {
|
if (code == 0) {
|
||||||
|
console.log(code);
|
||||||
term.write(new Uint8Array(stdout_buffer));
|
term.write(new Uint8Array(stdout_buffer));
|
||||||
stdout_buffer = [];
|
stdout_buffer = [];
|
||||||
} else {
|
} else {
|
||||||
|
@ -27,6 +27,11 @@ class Input : public Component {
|
|||||||
// Component implementation.
|
// Component implementation.
|
||||||
Element Render() override;
|
Element Render() override;
|
||||||
bool OnEvent(Event) override;
|
bool OnEvent(Event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool OnMouseEvent(Event);
|
||||||
|
Box input_box_;
|
||||||
|
Box cursor_box_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
@ -15,14 +15,15 @@ Element Input::Render() {
|
|||||||
// Placeholder.
|
// Placeholder.
|
||||||
if (content.size() == 0) {
|
if (content.size() == 0) {
|
||||||
if (is_focused)
|
if (is_focused)
|
||||||
return text(placeholder) | focus | dim | inverted | main_decorator;
|
return text(placeholder) | focus | dim | inverted | main_decorator |
|
||||||
|
reflect(input_box_);
|
||||||
else
|
else
|
||||||
return text(placeholder) | dim | main_decorator;
|
return text(placeholder) | dim | main_decorator | reflect(input_box_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not focused.
|
// Not focused.
|
||||||
if (!is_focused)
|
if (!is_focused)
|
||||||
return text(content) | main_decorator;
|
return text(content) | main_decorator | reflect(input_box_);
|
||||||
|
|
||||||
std::wstring part_before_cursor = content.substr(0, cursor_position);
|
std::wstring part_before_cursor = content.substr(0, cursor_position);
|
||||||
std::wstring part_at_cursor = cursor_position < (int)content.size()
|
std::wstring part_at_cursor = cursor_position < (int)content.size()
|
||||||
@ -37,13 +38,18 @@ Element Input::Render() {
|
|||||||
return
|
return
|
||||||
hbox(
|
hbox(
|
||||||
text(part_before_cursor),
|
text(part_before_cursor),
|
||||||
text(part_at_cursor) | underlined | focused,
|
text(part_at_cursor) | underlined | focused | reflect(cursor_box_),
|
||||||
text(part_after_cursor)
|
text(part_after_cursor)
|
||||||
) | flex | inverted | frame | main_decorator;
|
) | flex | inverted | frame | main_decorator | reflect(input_box_);
|
||||||
// clang-format off
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Input::OnEvent(Event event) {
|
bool Input::OnEvent(Event event) {
|
||||||
cursor_position = std::max(0, std::min<int>(content.size(), cursor_position));
|
cursor_position = std::max(0, std::min<int>(content.size(), cursor_position));
|
||||||
|
|
||||||
|
if (event.is_mouse())
|
||||||
|
return OnMouseEvent(event);
|
||||||
|
|
||||||
std::wstring c;
|
std::wstring c;
|
||||||
|
|
||||||
// Backspace.
|
// Backspace.
|
||||||
@ -95,6 +101,26 @@ bool Input::OnEvent(Event event) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Input::OnMouseEvent(Event event) {
|
||||||
|
if (!input_box_.Contain(event.mouse().x, event.mouse().y))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TakeFocus();
|
||||||
|
|
||||||
|
if (event.mouse().button == Mouse::Left &&
|
||||||
|
event.mouse().motion == Mouse::Pressed) {
|
||||||
|
int new_cursor_position =
|
||||||
|
cursor_position + event.mouse().x - cursor_box_.x_min;
|
||||||
|
new_cursor_position =
|
||||||
|
std::max(0, std::min<int>(content.size(), new_cursor_position));
|
||||||
|
if (cursor_position != new_cursor_position) {
|
||||||
|
cursor_position = new_cursor_position;
|
||||||
|
on_change();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ftxui
|
} // namespace ftxui
|
||||||
|
|
||||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||||
|
@ -40,7 +40,7 @@ namespace {
|
|||||||
|
|
||||||
void Flush() {
|
void Flush() {
|
||||||
// Emscripten doesn't implement flush. We interpret zero as flush.
|
// Emscripten doesn't implement flush. We interpret zero as flush.
|
||||||
std::cout << std::flush << (char)0;
|
std::cout << '\0' << std::flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int timeout_milliseconds = 20;
|
constexpr int timeout_milliseconds = 20;
|
||||||
@ -353,6 +353,8 @@ void ScreenInteractive::Loop(Component* component) {
|
|||||||
DECMode::kMouseSgrExtMode,
|
DECMode::kMouseSgrExtMode,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
flush();
|
||||||
|
|
||||||
auto event_listener =
|
auto event_listener =
|
||||||
std::thread(&EventListener, &quit_, event_receiver_->MakeSender());
|
std::thread(&EventListener, &quit_, event_receiver_->MakeSender());
|
||||||
|
|
||||||
|
@ -41,19 +41,23 @@ void TerminalInputParser::Send(TerminalInputParser::Output output) {
|
|||||||
|
|
||||||
case CHARACTER:
|
case CHARACTER:
|
||||||
out_->Send(Event::Character(std::move(pending_)));
|
out_->Send(Event::Character(std::move(pending_)));
|
||||||
|
pending_.clear();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case SPECIAL:
|
case SPECIAL:
|
||||||
out_->Send(Event::Special(std::move(pending_)));
|
out_->Send(Event::Special(std::move(pending_)));
|
||||||
|
pending_.clear();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case MOUSE:
|
case MOUSE:
|
||||||
out_->Send(Event::Mouse(std::move(pending_), output.mouse));
|
out_->Send(Event::Mouse(std::move(pending_), output.mouse));
|
||||||
|
pending_.clear();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case CURSOR_REPORTING:
|
case CURSOR_REPORTING:
|
||||||
out_->Send(Event::CursorReporting(std::move(pending_), output.cursor.x,
|
out_->Send(Event::CursorReporting(std::move(pending_), output.cursor.x,
|
||||||
output.cursor.y));
|
output.cursor.y));
|
||||||
|
pending_.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// NOT_REACHED().
|
// NOT_REACHED().
|
||||||
@ -133,7 +137,7 @@ TerminalInputParser::Output TerminalInputParser::ParseDCS() {
|
|||||||
|
|
||||||
TerminalInputParser::Output TerminalInputParser::ParseCSI() {
|
TerminalInputParser::Output TerminalInputParser::ParseCSI() {
|
||||||
bool altered = false;
|
bool altered = false;
|
||||||
int argument;
|
int argument = 0;
|
||||||
std::vector<int> arguments;
|
std::vector<int> arguments;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!Eat())
|
if (!Eat())
|
||||||
@ -205,9 +209,8 @@ TerminalInputParser::Output TerminalInputParser::ParseMouse(
|
|||||||
output.mouse.button = Mouse::Button((arguments[0] & 3) + //
|
output.mouse.button = Mouse::Button((arguments[0] & 3) + //
|
||||||
((arguments[0] & 64) >> 4));
|
((arguments[0] & 64) >> 4));
|
||||||
output.mouse.motion = Mouse::Motion(pressed);
|
output.mouse.motion = Mouse::Motion(pressed);
|
||||||
output.mouse.shift = arguments[0] & 4;
|
output.mouse.shift = bool(arguments[0] & 4);
|
||||||
output.mouse.meta = arguments[0] & 8;
|
output.mouse.meta = bool(arguments[0] & 8);
|
||||||
output.mouse.control = arguments[0] & 16;
|
|
||||||
output.mouse.x = arguments[1];
|
output.mouse.x = arguments[1];
|
||||||
output.mouse.y = arguments[2];
|
output.mouse.y = arguments[2];
|
||||||
return output;
|
return output;
|
||||||
|
@ -184,7 +184,7 @@ std::string Screen::ToString() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Screen::Print() {
|
void Screen::Print() {
|
||||||
std::cout << ToString() << std::flush << (char)0;
|
std::cout << ToString() << '\0' << std::flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Access a character a given position.
|
/// @brief Access a character a given position.
|
||||||
|
Loading…
Reference in New Issue
Block a user