Fix Clamp crash when entries_ size is zero (#306)

Run ftxui_example_homescreen on Windows, then select compiler tab, crash on origin code.

Co-authored-by: chenpeizhe <peizhe.chen@horizon.ai>
This commit is contained in:
pezy 2022-01-13 08:46:09 +08:00 committed by GitHub
parent 3dc215e6c0
commit feb24b9498
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 40 additions and 21 deletions

View File

@ -23,17 +23,18 @@ else()
endif() endif()
add_library(screen add_library(screen
include/ftxui/screen/box.hpp
include/ftxui/screen/color.hpp
include/ftxui/screen/color_info.hpp
include/ftxui/screen/screen.hpp
include/ftxui/screen/string.hpp
src/ftxui/screen/box.cpp src/ftxui/screen/box.cpp
src/ftxui/screen/color.cpp src/ftxui/screen/color.cpp
src/ftxui/screen/color_info.cpp src/ftxui/screen/color_info.cpp
src/ftxui/screen/screen.cpp src/ftxui/screen/screen.cpp
src/ftxui/screen/string.cpp src/ftxui/screen/string.cpp
src/ftxui/screen/terminal.cpp src/ftxui/screen/terminal.cpp
include/ftxui/screen/box.hpp src/ftxui/screen/util.hpp
include/ftxui/screen/color.hpp
include/ftxui/screen/color_info.hpp
include/ftxui/screen/screen.hpp
include/ftxui/screen/string.hpp
) )
add_library(dom add_library(dom

View File

@ -14,7 +14,8 @@
#include "ftxui/component/screen_interactive.hpp" // for Component #include "ftxui/component/screen_interactive.hpp" // for Component
#include "ftxui/dom/elements.hpp" // for operator|, Element, reflect, text, nothing, select, vbox, Elements, focus #include "ftxui/dom/elements.hpp" // for operator|, Element, reflect, text, nothing, select, vbox, Elements, focus
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
#include "ftxui/util/ref.hpp" // for Ref, ConstStringListRef, ConstStringRef #include "ftxui/screen/util.hpp"
#include "ftxui/util/ref.hpp" // for Ref, ConstStringListRef, ConstStringRef
namespace ftxui { namespace ftxui {
@ -74,7 +75,7 @@ class MenuBase : public ComponentBase {
if (event == Event::TabReverse && size()) if (event == Event::TabReverse && size())
*selected_ = (*selected_ + size() - 1) % size(); *selected_ = (*selected_ + size() - 1) % size();
*selected_ = std::clamp(*selected_, 0, size() - 1); *selected_ = util::clamp(*selected_, 0, size() - 1);
if (*selected_ != old_selected) { if (*selected_ != old_selected) {
focused_entry() = *selected_; focused_entry() = *selected_;
@ -131,7 +132,7 @@ class MenuBase : public ComponentBase {
if (event.mouse().button == Mouse::WheelDown) if (event.mouse().button == Mouse::WheelDown)
(*selected_)++; (*selected_)++;
*selected_ = std::clamp(*selected_, 0, size() - 1); *selected_ = util::clamp(*selected_, 0, size() - 1);
if (*selected_ != old_selected) if (*selected_ != old_selected)
option_->on_change(); option_->on_change();
@ -140,8 +141,8 @@ class MenuBase : public ComponentBase {
void Clamp() { void Clamp() {
boxes_.resize(size()); boxes_.resize(size());
*selected_ = std::clamp(*selected_, 0, size() - 1); *selected_ = util::clamp(*selected_, 0, size() - 1);
focused_entry() = std::clamp(focused_entry(), 0, size() - 1); focused_entry() = util::clamp(focused_entry(), 0, size() - 1);
} }
bool Focusable() const final { return entries_.size(); } bool Focusable() const final { return entries_.size(); }

View File

@ -14,7 +14,8 @@
#include "ftxui/component/screen_interactive.hpp" // for Component #include "ftxui/component/screen_interactive.hpp" // for Component
#include "ftxui/dom/elements.hpp" // for operator|, reflect, text, Element, hbox, vbox, Elements, focus, nothing, select #include "ftxui/dom/elements.hpp" // for operator|, reflect, text, Element, hbox, vbox, Elements, focus, nothing, select
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
#include "ftxui/util/ref.hpp" // for Ref, ConstStringListRef #include "ftxui/screen/util.hpp"
#include "ftxui/util/ref.hpp" // for Ref, ConstStringListRef
namespace ftxui { namespace ftxui {
@ -91,7 +92,7 @@ class RadioboxBase : public ComponentBase {
if (event == Event::TabReverse && size()) if (event == Event::TabReverse && size())
hovered_ = (hovered_ + size() - 1) % size(); hovered_ = (hovered_ + size() - 1) % size();
hovered_ = std::clamp(hovered_, 0, size() - 1); hovered_ = util::clamp(hovered_, 0, size() - 1);
if (hovered_ != old_hovered) { if (hovered_ != old_hovered) {
focused_entry() = hovered_; focused_entry() = hovered_;
@ -145,7 +146,7 @@ class RadioboxBase : public ComponentBase {
if (event.mouse().button == Mouse::WheelDown) if (event.mouse().button == Mouse::WheelDown)
(hovered_)++; (hovered_)++;
hovered_ = std::clamp(hovered_, 0, size() - 1); hovered_ = util::clamp(hovered_, 0, size() - 1);
if (hovered_ != old_hovered) if (hovered_ != old_hovered)
option_->on_change(); option_->on_change();
@ -155,9 +156,9 @@ class RadioboxBase : public ComponentBase {
void Clamp() { void Clamp() {
boxes_.resize(size()); boxes_.resize(size());
*selected_ = std::clamp(*selected_, 0, size() - 1); *selected_ = util::clamp(*selected_, 0, size() - 1);
focused_entry() = std::clamp(focused_entry(), 0, size() - 1); focused_entry() = util::clamp(focused_entry(), 0, size() - 1);
hovered_ = std::clamp(hovered_, 0, size() - 1); hovered_ = util::clamp(hovered_, 0, size() - 1);
} }
bool Focusable() const final { return entries_.size(); } bool Focusable() const final { return entries_.size(); }

View File

@ -12,7 +12,8 @@
#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed
#include "ftxui/dom/elements.hpp" // for operator|, Element, Elements, hbox, reflect, separator, text, focus, nothing, select #include "ftxui/dom/elements.hpp" // for operator|, Element, Elements, hbox, reflect, separator, text, focus, nothing, select
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
#include "ftxui/util/ref.hpp" // for Ref, ConstStringListRef #include "ftxui/screen/util.hpp"
#include "ftxui/util/ref.hpp" // for Ref, ConstStringListRef
namespace ftxui { namespace ftxui {
@ -68,7 +69,7 @@ class ToggleBase : public ComponentBase {
if (event == Event::TabReverse && size()) if (event == Event::TabReverse && size())
*selected_ = (*selected_ + size() - 1) % size(); *selected_ = (*selected_ + size() - 1) % size();
*selected_ = std::clamp(*selected_, 0, size() - 1); *selected_ = util::clamp(*selected_, 0, size() - 1);
if (old_selected != *selected_) { if (old_selected != *selected_) {
focused_entry() = *selected_; focused_entry() = *selected_;
@ -108,8 +109,8 @@ class ToggleBase : public ComponentBase {
void Clamp() { void Clamp() {
boxes_.resize(size()); boxes_.resize(size());
*selected_ = std::clamp(*selected_, 0, size() - 1); *selected_ = util::clamp(*selected_, 0, size() - 1);
focused_entry() = std::clamp(focused_entry(), 0, size() - 1); focused_entry() = util::clamp(focused_entry(), 0, size() - 1);
} }
bool Focusable() const final { return size(); } bool Focusable() const final { return size(); }

15
src/ftxui/screen/util.hpp Normal file
View File

@ -0,0 +1,15 @@
namespace ftxui {
namespace util {
// Similar to std::clamp, but allow hi to be lower than lo.
template <class T>
constexpr const T& clamp(const T& v, const T& lo, const T& hi) {
return v < lo ? lo : hi < v ? hi : v;
}
} // namespace util
} // namespace ftxui
// Copyright 2022 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

View File

@ -1,4 +1,4 @@
// Copyright 2021 Arthur Sonzogni. All rights reserved. // Copyright 2022 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in // Use of this source code is governed by the MIT license that can be found in
// the LICENSE file. // the LICENSE file.