Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/windowing/StarTextBoxWidget.cpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
commit6352e8e3196f78388b6c771073f9e03eaa612673 (patch)
treee23772f79a7fbc41bc9108951e9e136857484bf4 /source/windowing/StarTextBoxWidget.cpp
parent6741a057e5639280d85d0f88ba26f000baa58f61 (diff)
everything everywhere
all at once
Diffstat (limited to 'source/windowing/StarTextBoxWidget.cpp')
-rw-r--r--source/windowing/StarTextBoxWidget.cpp393
1 files changed, 393 insertions, 0 deletions
diff --git a/source/windowing/StarTextBoxWidget.cpp b/source/windowing/StarTextBoxWidget.cpp
new file mode 100644
index 0000000..bed6c5e
--- /dev/null
+++ b/source/windowing/StarTextBoxWidget.cpp
@@ -0,0 +1,393 @@
+#include "StarTextBoxWidget.hpp"
+#include "StarRoot.hpp"
+#include "StarJsonExtra.hpp"
+#include "StarAssets.hpp"
+
+namespace Star {
+
+TextBoxWidget::TextBoxWidget(String const& startingText, String const& hint, WidgetCallbackFunc callback)
+ : m_text(startingText), m_hint(hint), m_callback(callback) {
+ m_regex = ".*";
+ m_repeatKeyThreshold = 0;
+ m_repeatCode = SpecialRepeatKeyCodes::None;
+ m_isPressed = false;
+ m_isHover = false;
+ m_cursorOffset = startingText.size();
+ m_hAnchor = HorizontalAnchor::LeftAnchor;
+ m_vAnchor = VerticalAnchor::BottomAnchor;
+ m_color = Color::rgbf(1, 1, 1);
+ m_drawBorder = false;
+ m_cursorHoriz = Vec2I();
+ m_cursorVert = Vec2I();
+ m_overfillMode = true;
+
+ auto assets = Root::singleton().assets();
+
+ m_maxWidth = assets->json("/interface.config:textBoxDefaultWidth").toInt();
+ m_fontSize = assets->json("/interface.config:font.baseSize").toInt();
+
+ // Meh, padding is hard-coded here
+ setSize({m_maxWidth + 6, m_fontSize + 2});
+ m_cursorHoriz = jsonToVec2I(assets->json("/interface.config:textboxCursorHorizontal"));
+ m_cursorVert = jsonToVec2I(assets->json("/interface.config:textboxCursorVertical"));
+}
+
+void TextBoxWidget::renderImpl() {
+ float blueRate = 0;
+ if (m_isHover && !m_isPressed)
+ blueRate = 0.2f;
+ else
+ blueRate = 0.0f;
+
+ Vec2F pos(screenPosition());
+ if (m_hAnchor == HorizontalAnchor::HMidAnchor)
+ pos += Vec2F(size()[0] / 2.0f, 0);
+ else if (m_hAnchor == HorizontalAnchor::RightAnchor)
+ pos += Vec2F(size()[0], 0);
+
+ if ((m_maxWidth != -1) && m_overfillMode) {
+ context()->setFontSize(m_fontSize);
+ int shift = std::max(0, getCursorOffset() - m_maxWidth);
+ pos += Vec2F(-shift, 0);
+ }
+
+ context()->setFontSize(m_fontSize);
+ if (m_text.empty()) {
+ context()->setFontColor(m_color.mix(Color::rgbf(0.3f, 0.3f, 0.3f), 0.8f).mix(Color::rgbf(0.0f, 0.0f, 1.0f), blueRate).toRgba());
+ context()->renderInterfaceText(m_hint, {pos, m_hAnchor, m_vAnchor});
+ } else {
+ context()->setFontColor(m_color.mix(Color::rgbf(0, 0, 1), blueRate).toRgba());
+ context()->renderInterfaceText(m_text, {pos, m_hAnchor, m_vAnchor});
+ }
+ context()->setFontColor(Vec4B::filled(255));
+
+ if (hasFocus()) {
+ // render cursor
+ float cc = 0.6f + 0.4f * std::sin((double)Time::monotonicMilliseconds() / 300.0);
+ Color cursorColor = Color::rgbf(cc, cc, cc);
+
+ context()->drawInterfaceLine(
+ pos + Vec2F(getCursorOffset(), m_fontSize * m_cursorVert[0]),
+ pos + Vec2F(getCursorOffset(), m_fontSize * m_cursorVert[1]),
+ cursorColor.toRgba());
+ context()->drawInterfaceLine(
+ pos + Vec2F(getCursorOffset() + m_fontSize * m_cursorHoriz[0], m_fontSize * m_cursorVert[0]),
+ pos + Vec2F(getCursorOffset() + m_fontSize * m_cursorHoriz[1], m_fontSize * m_cursorVert[0]),
+ cursorColor.toRgba());
+ }
+
+ if (m_drawBorder)
+ context()->drawInterfacePolyLines(PolyF(screenBoundRect()), Color(Color::White).toRgba());
+}
+
+int TextBoxWidget::getCursorOffset() { // horizontal only
+ float scale;
+ context()->setFontSize(m_fontSize);
+ if (m_hAnchor == HorizontalAnchor::LeftAnchor) {
+ scale = 1.0;
+ } else if (m_hAnchor == HorizontalAnchor::HMidAnchor) {
+ scale = 0.5;
+ } else if (m_hAnchor == HorizontalAnchor::RightAnchor) {
+ scale = -1.0;
+ return context()->stringInterfaceWidth(m_text) * scale
+ + context()->stringInterfaceWidth(m_text.substr(m_cursorOffset, m_text.size()));
+ } else {
+ throw GuiException("Somehow, the value of m_hAnchor became bad");
+ }
+
+ return (int)std::ceil(context()->stringInterfaceWidth(m_text) * scale
+ - context()->stringInterfaceWidth(m_text.substr(m_cursorOffset, m_text.size())));
+}
+
+void TextBoxWidget::update() {
+ Widget::update();
+ if (m_repeatCode != SpecialRepeatKeyCodes::None) {
+ if (Time::monotonicMilliseconds() >= m_repeatKeyThreshold) {
+ m_repeatKeyThreshold += 50;
+ if (m_repeatCode == SpecialRepeatKeyCodes::Delete) {
+ if (m_cursorOffset < (int)m_text.size())
+ modText(m_text.substr(0, m_cursorOffset) + m_text.substr(m_cursorOffset + 1));
+ } else if (m_repeatCode == SpecialRepeatKeyCodes::Backspace) {
+ if (m_cursorOffset > 0) {
+ if (modText(m_text.substr(0, m_cursorOffset - 1) + m_text.substr(m_cursorOffset)))
+ m_cursorOffset -= 1;
+ }
+ } else if (m_repeatCode == SpecialRepeatKeyCodes::Left) {
+ if (m_cursorOffset > 0) {
+ m_cursorOffset--;
+ if (m_cursorOffset < 0)
+ m_cursorOffset = 0;
+ }
+ } else if (m_repeatCode == SpecialRepeatKeyCodes::Right) {
+ if (m_cursorOffset < (int)m_text.size()) {
+ m_cursorOffset++;
+ if (m_cursorOffset > (int)m_text.size())
+ m_cursorOffset = m_text.size();
+ }
+ }
+ }
+ }
+}
+
+String TextBoxWidget::getText() {
+ return m_text;
+}
+
+bool TextBoxWidget::setText(String const& text, bool callback) {
+ if (m_text == text)
+ return true;
+
+ if (!newTextValid(text))
+ return false;
+
+ m_text = text;
+ m_cursorOffset = m_text.size();
+ m_repeatCode = SpecialRepeatKeyCodes::None;
+ if (callback)
+ m_callback(this);
+ return true;
+}
+
+String TextBoxWidget::getRegex() {
+ return m_regex;
+}
+
+void TextBoxWidget::setRegex(String const& regex) {
+ m_regex = regex;
+}
+
+void TextBoxWidget::setColor(Color const& color) {
+ m_color = color;
+}
+
+void TextBoxWidget::setFontSize(int fontSize) {
+ m_fontSize = fontSize;
+}
+
+void TextBoxWidget::setMaxWidth(int maxWidth) {
+ m_maxWidth = maxWidth;
+ setSize({m_maxWidth + 6, m_fontSize + 2});
+}
+
+void TextBoxWidget::setOverfillMode(bool overtype) {
+ m_overfillMode = overtype;
+}
+
+void TextBoxWidget::setOnBlurCallback(WidgetCallbackFunc onBlur) {
+ m_onBlur = onBlur;
+}
+
+void TextBoxWidget::setOnEnterKeyCallback(WidgetCallbackFunc onEnterKey) {
+ m_onEnterKey = onEnterKey;
+}
+
+void TextBoxWidget::setOnEscapeKeyCallback(WidgetCallbackFunc onEscapeKey) {
+ m_onEscapeKey = onEscapeKey;
+}
+
+void TextBoxWidget::setNextFocus(Maybe<String> nextFocus) {
+ m_nextFocus = nextFocus;
+}
+
+void TextBoxWidget::setPrevFocus(Maybe<String> prevFocus) {
+ m_prevFocus = prevFocus;
+}
+
+void TextBoxWidget::mouseOver() {
+ Widget::mouseOver();
+ m_isHover = true;
+}
+
+void TextBoxWidget::mouseOut() {
+ Widget::mouseOut();
+ m_isHover = false;
+ m_isPressed = false;
+}
+
+void TextBoxWidget::mouseReturnStillDown() {
+ Widget::mouseReturnStillDown();
+ m_isHover = true;
+ m_isPressed = true;
+}
+
+void TextBoxWidget::blur() {
+ Widget::blur();
+ if (m_onBlur)
+ m_onBlur(this);
+ m_repeatCode = SpecialRepeatKeyCodes::None;
+}
+
+KeyboardCaptureMode TextBoxWidget::keyboardCaptured() const {
+ if (active() && hasFocus())
+ return KeyboardCaptureMode::TextInput;
+ return KeyboardCaptureMode::None;
+}
+
+bool TextBoxWidget::sendEvent(InputEvent const& event) {
+ if (!hasFocus())
+ return false;
+
+ if (event.is<KeyUpEvent>()) {
+ m_repeatCode = SpecialRepeatKeyCodes::None;
+ m_callback(this);
+ return false;
+ }
+
+ if (innerSendEvent(event)) {
+ m_callback(this);
+ return true;
+ }
+
+ return false;
+}
+
+bool TextBoxWidget::innerSendEvent(InputEvent const& event) {
+ if (auto keyDown = event.ptr<KeyDownEvent>()) {
+ m_repeatKeyThreshold = Time::monotonicMilliseconds() + 300LL;
+
+ if (keyDown->key == Key::Escape) {
+ if (m_onEscapeKey) {
+ m_onEscapeKey(this);
+ return true;
+ }
+ return false;
+ }
+ if (keyDown->key == Key::Return || keyDown->key == Key::Kp_enter) {
+ if (m_onEnterKey) {
+ m_onEnterKey(this);
+ return true;
+ }
+ return false;
+ }
+ if (keyDown->key == Key::Tab) {
+ if ((KeyMod::LShift & keyDown->mods) == KeyMod::LShift || (KeyMod::RShift & keyDown->mods) == KeyMod::RShift) {
+ if (m_prevFocus) {
+ if (auto prevWidget = parent()->fetchChild(*m_prevFocus)) {
+ prevWidget->focus();
+ return true;
+ }
+ }
+ } else {
+ if (m_nextFocus) {
+ if (auto nextWidget = parent()->fetchChild(*m_nextFocus)) {
+ nextWidget->focus();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ if ((keyDown->mods & (KeyMod::LCtrl | KeyMod::RCtrl)) != KeyMod::NoMod) {
+ if (keyDown->key == Key::C) {
+ context()->setClipboard(m_text);
+ return true;
+ }
+ if (keyDown->key == Key::X) {
+ context()->setClipboard(m_text);
+ if (modText(""))
+ m_cursorOffset = 0;
+ return true;
+ }
+ if (keyDown->key == Key::V) {
+ String clipboard = context()->getClipboard();
+ if (modText(m_text.substr(0, m_cursorOffset) + clipboard + m_text.substr(m_cursorOffset)))
+ m_cursorOffset += clipboard.size();
+ return true;
+ }
+ }
+
+ int rightSteps = 1;
+ int leftSteps = 1;
+ if ((keyDown->mods & (KeyMod::LCtrl | KeyMod::RCtrl)) != KeyMod::NoMod || (keyDown->mods & (KeyMod::LAlt | KeyMod::RAlt)) != KeyMod::NoMod) {
+ rightSteps = m_text.findNextBoundary(m_cursorOffset) - m_cursorOffset;
+ leftSteps = m_cursorOffset - m_text.findNextBoundary(m_cursorOffset, true);
+
+ if (rightSteps < 1)
+ rightSteps = 1;
+ if (leftSteps < 1)
+ leftSteps = 1;
+ }
+
+ if (keyDown->key == Key::Backspace) {
+ m_repeatCode = SpecialRepeatKeyCodes::Backspace;
+ for (int i = 0; i < leftSteps; i++) {
+ if (m_cursorOffset > 0) {
+ if (modText(m_text.substr(0, m_cursorOffset - 1) + m_text.substr(m_cursorOffset)))
+ m_cursorOffset -= 1;
+ }
+ }
+ return true;
+ }
+ if (keyDown->key == Key::Delete) {
+ m_repeatCode = SpecialRepeatKeyCodes::Delete;
+ for (int i = 0; i < rightSteps; i++) {
+ if (m_cursorOffset < (int)m_text.size())
+ modText(m_text.substr(0, m_cursorOffset) + m_text.substr(m_cursorOffset + 1));
+ }
+ return true;
+ }
+ if (keyDown->key == Key::Left) {
+ m_repeatCode = SpecialRepeatKeyCodes::Left;
+ for (int i = 0; i < leftSteps; i++) {
+ m_cursorOffset--;
+ if (m_cursorOffset < 0)
+ m_cursorOffset = 0;
+ }
+ return true;
+ }
+ if (keyDown->key == Key::Right) {
+ m_repeatCode = SpecialRepeatKeyCodes::Right;
+ for (int i = 0; i < rightSteps; i++) {
+ m_cursorOffset++;
+ if (m_cursorOffset > (int)m_text.size())
+ m_cursorOffset = m_text.size();
+ }
+ return true;
+ }
+ if (keyDown->key == Key::Home) {
+ m_cursorOffset = 0;
+ return true;
+ }
+ if (keyDown->key == Key::End) {
+ m_cursorOffset = m_text.size();
+ return true;
+ }
+ }
+
+ if (auto textInput = event.ptr<TextInputEvent>()) {
+ if (modText(m_text.substr(0, m_cursorOffset) + textInput->text + m_text.substr(m_cursorOffset)))
+ m_cursorOffset += textInput->text.size();
+ return true;
+ }
+
+ return false;
+}
+
+void TextBoxWidget::setDrawBorder(bool drawBorder) {
+ m_drawBorder = drawBorder;
+}
+
+void TextBoxWidget::setTextAlign(HorizontalAnchor hAnchor) {
+ m_hAnchor = hAnchor;
+}
+
+bool TextBoxWidget::modText(String const& text) {
+ if (m_text != text && newTextValid(text)) {
+ m_text = text;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool TextBoxWidget::newTextValid(String const& text) const {
+ if (!text.regexMatch(m_regex))
+ return false;
+ if ((m_maxWidth != -1) && !m_overfillMode) {
+ context()->setFontSize(m_fontSize);
+ return context()->stringInterfaceWidth(text) <= m_maxWidth;
+ }
+ return true;
+}
+
+}