Skip to content

Commit

Permalink
[Render/Overlay] Added an overlay text area widget
Browse files Browse the repository at this point in the history
- The overlay textbox can now take an initial text
  • Loading branch information
Razakhel committed Nov 19, 2023
1 parent bf9b0cb commit 8f2bcfa
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 11 deletions.
43 changes: 38 additions & 5 deletions include/RaZ/Render/Overlay.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum class OverlayElementType {
CHECKBOX,
SLIDER,
TEXTBOX,
TEXT_AREA,
LIST_BOX,
DROPDOWN,
TEXTURE,
Expand Down Expand Up @@ -184,7 +185,8 @@ class OverlayTextbox final : public OverlayElement {
friend OverlayWindow;

public:
OverlayTextbox(std::string label, std::function<void(const std::string&)> callback) : OverlayElement(std::move(label)), m_callback{ std::move(callback) } {}
OverlayTextbox(std::string label, std::function<void(const std::string&)> callback, std::string initText = {})
: OverlayElement(std::move(label)), m_text{ std::move(initText) }, m_callback{ std::move(callback) } {}

OverlayElementType getType() const override { return OverlayElementType::TEXTBOX; }
const std::string& getText() const noexcept { return m_text; }
Expand All @@ -201,6 +203,29 @@ class OverlayTextbox final : public OverlayElement {
std::function<void(const std::string&)> m_callback {};
};

class OverlayTextArea final : public OverlayElement {
friend OverlayWindow;

public:
OverlayTextArea(std::string label, std::function<void(const std::string&)> callback, std::string initText = {}, float maxHeight = -1.f)
: OverlayElement(std::move(label)), m_text{ std::move(initText) }, m_callback{ std::move(callback) }, m_maxHeight{ maxHeight } {}

OverlayElementType getType() const override { return OverlayElementType::TEXT_AREA; }
const std::string& getText() const noexcept { return m_text; }

void setText(std::string text);

OverlayTextArea& append(const std::string& text);
void clear();

OverlayTextArea& operator+=(const std::string& text) { return append(text); }

private:
std::string m_text {};
std::function<void(const std::string&)> m_callback {};
float m_maxHeight {};
};

class OverlayListBox final : public OverlayElement {
friend OverlayWindow;

Expand Down Expand Up @@ -409,11 +434,19 @@ class OverlayWindow {
/// \param initValue Initial value.
/// \return Reference to the newly added slider.
OverlaySlider& addSlider(std::string label, std::function<void(float)> actionSlide, float minValue, float maxValue, float initValue);
/// Adds a texbox on the overlay window.
/// \param label Text to be displayed beside the checkbox.
/// Adds a textbox on the overlay window.
/// \param label Text to be displayed beside the textbox.
/// \param callback Function to be called every time the content is modified.
/// \param initText Initial text to be set.
/// \return Reference to the newly added textbox.
OverlayTextbox& addTextbox(std::string label, std::function<void(const std::string&)> callback);
OverlayTextbox& addTextbox(std::string label, std::function<void(const std::string&)> callback, std::string initText = {});
/// Adds a text area on the overlay window.
/// \param label Text to be displayed beside the text area.
/// \param callback Function to be called every time the content is modified.
/// \param initText Initial text to be set.
/// \param maxHeight Maximum height. If strictly lower than 0, automatically resizes the widget to fit the window's content.
/// \return Reference to the newly added text area.
OverlayTextArea& addTextArea(std::string label, std::function<void(const std::string&)> callback, std::string initText = {}, float maxHeight = -1.f);
/// Adds a list box on the overlay window.
/// \param label Text to be displayed beside the list.
/// \param entries Texts to fill the list with.
Expand Down Expand Up @@ -454,7 +487,7 @@ class OverlayWindow {
/// \param minYVal Minimum value on the Y (vertical) axis.
/// \param maxYVal Maximum value on the Y (vertical) axis.
/// \param lockYAxis Whether to allow panning & zooming on the Y (vertical) axis.
/// \param maxHeight Maximum height of the plot widget. If strictly lower than 0, automatically resizes the plot to fit the window's content.
/// \param maxHeight Maximum height. If strictly lower than 0, automatically resizes the widget to fit the window's content.
/// \return Reference to the newly added plot.
[[nodiscard]] OverlayPlot& addPlot(std::string label, std::size_t maxValCount,
std::string xAxisLabel = {}, std::string yAxisLabel = {},
Expand Down
48 changes: 45 additions & 3 deletions src/RaZ/Render/Overlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,23 @@ void OverlayTextbox::clear() {
m_callback(m_text);
}

void OverlayTextArea::setText(std::string text) {
m_text = std::move(text);
m_callback(m_text);
}

OverlayTextArea& OverlayTextArea::append(const std::string& text) {
m_text += text;
m_callback(m_text);

return *this;
}

void OverlayTextArea::clear() {
m_text.clear();
m_callback(m_text);
}

OverlayTexture::OverlayTexture(const Texture2D& texture)
: OverlayTexture(texture, texture.getWidth(), texture.getHeight()) {}

Expand Down Expand Up @@ -155,12 +172,23 @@ OverlaySlider& OverlayWindow::addSlider(std::string label, std::function<void(fl
minValue, maxValue, initValue)));
}

OverlayTextbox& OverlayWindow::addTextbox(std::string label, std::function<void(const std::string&)> callback) {
auto& textbox = static_cast<OverlayTextbox&>(*m_elements.emplace_back(std::make_unique<OverlayTextbox>(std::move(label), std::move(callback))));
textbox.m_text.reserve(64);
OverlayTextbox& OverlayWindow::addTextbox(std::string label, std::function<void(const std::string&)> callback, std::string initText) {
auto& textbox = static_cast<OverlayTextbox&>(*m_elements.emplace_back(std::make_unique<OverlayTextbox>(std::move(label),
std::move(callback),
std::move(initText))));
textbox.m_text.reserve(std::min(textbox.m_text.size(), static_cast<std::size_t>(64)));
return textbox;
}

OverlayTextArea& OverlayWindow::addTextArea(std::string label, std::function<void(const std::string&)> callback, std::string initText, float maxHeight) {
auto& textArea = static_cast<OverlayTextArea&>(*m_elements.emplace_back(std::make_unique<OverlayTextArea>(std::move(label),
std::move(callback),
std::move(initText),
maxHeight)));
textArea.m_text.reserve(std::min(textArea.m_text.size(), static_cast<std::size_t>(2048)));
return textArea;
}

OverlayListBox& OverlayWindow::addListBox(std::string label, std::vector<std::string> entries,
std::function<void(const std::string&, std::size_t)> actionChanged, std::size_t initId) {
if (entries.empty())
Expand Down Expand Up @@ -294,6 +322,20 @@ void OverlayWindow::render() const {
break;
}

case OverlayElementType::TEXT_AREA:
{
auto& textArea = static_cast<OverlayTextArea&>(*element);

if (ImGui::InputTextMultiline(textArea.m_label.c_str(),
&textArea.m_text,
ImVec2(-1.f, textArea.m_maxHeight),
ImGuiInputTextFlags_AllowTabInput)) {
textArea.m_callback(textArea.m_text);
}

break;
}

case OverlayElementType::LIST_BOX:
{
auto& listBox = static_cast<OverlayListBox&>(*element);
Expand Down
37 changes: 35 additions & 2 deletions src/RaZ/Script/LuaOverlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,33 @@ void LuaWrapper::registerOverlayTypes() {
sol::base_classes, sol::bases<OverlayElement>());
}

{
sol::usertype<OverlayTextArea> overlayTextArea = state.new_usertype<OverlayTextArea>("OverlayTextArea",
sol::constructors<
OverlayTextArea(std::string,
std::function<void(const std::string&)>),
OverlayTextArea(std::string,
std::function<void(const std::string&)>,
std::string),
OverlayTextArea(std::string,
std::function<void(const std::string&)>,
std::string,
float)
>(),
sol::base_classes, sol::bases<OverlayElement>());
overlayTextArea["text"] = sol::property(&OverlayTextArea::getText, &OverlayTextArea::setText);
overlayTextArea["append"] = &OverlayTextArea::append;
overlayTextArea["clear"] = &OverlayTextArea::clear;
}

{
sol::usertype<OverlayTextbox> overlayTextbox = state.new_usertype<OverlayTextbox>("OverlayTextbox",
sol::constructors<
OverlayTextbox(std::string,
std::function<void(const std::string&)>)
std::function<void(const std::string&)>),
OverlayTextbox(std::string,
std::function<void(const std::string&)>,
std::string)
>(),
sol::base_classes, sol::bases<OverlayElement>());
overlayTextbox["text"] = sol::property(&OverlayTextbox::getText, &OverlayTextbox::setText);
Expand Down Expand Up @@ -191,7 +213,17 @@ void LuaWrapper::registerOverlayTypes() {
overlayWindow["addButton"] = &OverlayWindow::addButton;
overlayWindow["addCheckbox"] = &OverlayWindow::addCheckbox;
overlayWindow["addSlider"] = &OverlayWindow::addSlider;
overlayWindow["addTextbox"] = &OverlayWindow::addTextbox;
overlayWindow["addTextbox"] = sol::overload([] (OverlayWindow& w, std::string l,
std::function<void(const std::string&)> c) { return &w.addTextbox(std::move(l),
std::move(c)); },
PickOverload<std::string, std::function<void(const std::string&)>,
std::string>(&OverlayWindow::addTextbox));
overlayWindow["addTextArea"] = sol::overload([] (OverlayWindow& w, std::string l,
std::function<void(const std::string&)> c) { return &w.addTextArea(std::move(l), std::move(c)); },
[] (OverlayWindow& w, std::string l, std::function<void(const std::string&)> c,
std::string t) { return &w.addTextArea(std::move(l), std::move(c), std::move(t)); },
PickOverload<std::string, std::function<void(const std::string&)>,
std::string, float>(&OverlayWindow::addTextArea));
overlayWindow["addListBox"] = sol::overload([] (OverlayWindow& w, std::string l, std::vector<std::string> e,
std::function<void(const std::string&, std::size_t)> c) { return &w.addListBox(std::move(l),
std::move(e),
Expand Down Expand Up @@ -234,6 +266,7 @@ void LuaWrapper::registerOverlayTypes() {
{ "CHECKBOX", OverlayElementType::CHECKBOX },
{ "SLIDER", OverlayElementType::SLIDER },
{ "TEXTBOX", OverlayElementType::TEXTBOX },
{ "TEXT_AREA", OverlayElementType::TEXT_AREA },
{ "LIST_BOX", OverlayElementType::LIST_BOX },
{ "DROPDOWN", OverlayElementType::DROPDOWN },
{ "TEXTURE", OverlayElementType::TEXTURE },
Expand Down
Binary file modified tests/assets/renders/overlay1_base.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/assets/renders/overlay4_base.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 11 additions & 1 deletion tests/src/RaZ/Render/RenderSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ TEST_CASE("RenderSystem overlay render") {
overlay1.addButton("Button", [] () noexcept {});
overlay1.addCheckbox("Checkbox on", [] () noexcept {}, [] () noexcept {}, true);
overlay1.addCheckbox("Checkbox off", [] () noexcept {}, [] () noexcept {}, false);
overlay1.addTextbox("Textbox", [] (const std::string&) noexcept {});
overlay1.addTextbox("Textbox", [] (const std::string&) noexcept {}, "initial").append(" text");

CHECK_THAT(renderFrame(world), IsNearlyEqualToImage(Raz::ImageFormat::load(RAZ_TESTS_ROOT "assets/renders/overlay1_base.png", true)));

Expand Down Expand Up @@ -156,5 +156,15 @@ TEST_CASE("RenderSystem overlay render") {

overlay3.disable();
}

{
Raz::OverlayWindow& overlay4 = window.getOverlay().addWindow("RaZ - Overlay test 4", Raz::Vec2f(window.getWidth(), window.getHeight()));
overlay4.addTextArea("Text area", [] (const std::string&) noexcept {}, "initial text", 25.f) += "\nmultiline";

// The text area's vertical scrollbar seems to be only rendered from the 2d frame onward
CHECK_THAT(renderFrame(world), IsNearlyEqualToImage(Raz::ImageFormat::load(RAZ_TESTS_ROOT "assets/renders/overlay4_base.png", true)));

overlay4.disable();
}
}
#endif
18 changes: 18 additions & 0 deletions tests/src/RaZ/Script/LuaRender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,26 @@ TEST_CASE("LuaRender Overlay") {
overlaySlider:disable()
assert(not overlaySlider:isEnabled())
local overlayTextArea = OverlayTextArea.new("", function () end)
overlayTextArea = OverlayTextArea.new("", function () end, "init")
overlayTextArea = OverlayTextArea.new("", function () end, "init", -1.0)
overlayTextArea = overlayWindow:addTextArea("", function () end)
overlayTextArea = overlayWindow:addTextArea("", function () end, "init")
overlayTextArea = overlayWindow:addTextArea("", function () end, "init", -1.0)
assert(overlayTextArea:getType() == OverlayElementType.TEXT_AREA)
overlayTextArea:enable()
overlayTextArea:enable(true)
overlayTextArea:disable()
assert(not overlayTextArea:isEnabled())
overlayTextArea.text = "text"
overlayTextArea:append(" test")
assert(overlayTextArea.text == "text test")
overlayTextArea:clear()
local overlayTextbox = OverlayTextbox.new("", function () end)
overlayTextbox = OverlayTextbox.new("", function () end, "init")
overlayTextbox = overlayWindow:addTextbox("", function () end)
overlayTextbox = overlayWindow:addTextbox("", function () end, "init")
assert(overlayTextbox:getType() == OverlayElementType.TEXTBOX)
overlayTextbox:enable()
overlayTextbox:enable(true)
Expand Down

0 comments on commit 8f2bcfa

Please sign in to comment.