// ---------------------------------------------------------------------------- // - Open3D: www.open3d.org - // ---------------------------------------------------------------------------- // The MIT License (MIT) // // Copyright (c) 2018 www.open3d.org // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. // ---------------------------------------------------------------------------- #include "Open3D/GUI/TextEdit.h" #include #include #include #include #include "Open3D/GUI/Theme.h" #include "Open3D/GUI/Util.h" namespace open3d { namespace gui { namespace { static int g_next_text_edit_id = 1; // See 3rdparty/imgui/misc/imgui_stdlib.cpp int InputTextCallback(ImGuiInputTextCallbackData *data) { if (data && data->EventFlag == ImGuiInputTextFlags_CallbackResize) { std::string *s = reinterpret_cast(data->UserData); s->resize(data->BufTextLen); data->Buf = const_cast(s->c_str()); } return 0; } } // namespace struct TextEdit::Impl { std::string id_; std::string text_; std::string placeholder_; std::function on_text_changed_; std::function on_value_changed_; }; TextEdit::TextEdit() : impl_(new TextEdit::Impl()) { std::stringstream s; s << "##textedit_" << g_next_text_edit_id++; impl_->id_ = s.str(); impl_->text_.reserve(1); } TextEdit::~TextEdit() {} const char *TextEdit::GetText() const { return impl_->text_.c_str(); } void TextEdit::SetText(const char *text) { impl_->text_ = text; } const char *TextEdit::GetPlaceholderText() const { return impl_->placeholder_.c_str(); } void TextEdit::SetPlaceholderText(const char *text) { impl_->placeholder_ = text; } void TextEdit::SetOnTextChanged( std::function on_text_changed) { impl_->on_text_changed_ = on_text_changed; } void TextEdit::SetOnValueChanged( std::function on_value_changed) { impl_->on_value_changed_ = on_value_changed; } bool TextEdit::ValidateNewText(const char *text) { return true; } Size TextEdit::CalcPreferredSize(const Theme &theme) const { auto em = std::ceil(ImGui::GetTextLineHeight()); auto padding = ImGui::GetStyle().FramePadding; return Size(Widget::DIM_GROW, std::ceil(em + 2.0f * padding.y)); } Widget::DrawResult TextEdit::Draw(const DrawContext &context) { auto &frame = GetFrame(); ImGui::SetCursorPos( ImVec2(frame.x - context.uiOffsetX, frame.y - context.uiOffsetY)); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0); // macOS doesn't round text editing ImGui::PushStyleColor( ImGuiCol_FrameBg, util::colorToImgui(context.theme.text_edit_background_color)); ImGui::PushStyleColor( ImGuiCol_FrameBgHovered, util::colorToImgui(context.theme.text_edit_background_color)); ImGui::PushStyleColor( ImGuiCol_FrameBgActive, util::colorToImgui(context.theme.text_edit_background_color)); int text_flags = ImGuiInputTextFlags_CallbackResize; if (!IsEnabled()) { text_flags = ImGuiInputTextFlags_ReadOnly; } auto result = Widget::DrawResult::NONE; DrawImGuiPushEnabledState(); ImGui::PushItemWidth(GetFrame().width); if (ImGui::InputTextWithHint(impl_->id_.c_str(), impl_->placeholder_.c_str(), const_cast(impl_->text_.c_str()), impl_->text_.capacity(), text_flags, InputTextCallback, &impl_->text_)) { if (impl_->on_text_changed_) { impl_->on_text_changed_(impl_->text_.c_str()); } result = Widget::DrawResult::REDRAW; } ImGui::PopItemWidth(); DrawImGuiPopEnabledState(); ImGui::PopStyleColor(3); ImGui::PopStyleVar(); if (ImGui::IsItemDeactivatedAfterEdit()) { if (ValidateNewText(impl_->text_.c_str())) { if (impl_->on_value_changed_) { impl_->on_value_changed_(impl_->text_.c_str()); } } // ValidateNewText() may have updated text (even if returned true) result = Widget::DrawResult::REDRAW; } return result; } } // namespace gui } // namespace open3d