Moved textbox input code out of InputManager
This commit is contained in:
parent
df3a78be1f
commit
262bf23bce
19 changed files with 343 additions and 329 deletions
|
|
@ -52,6 +52,7 @@ set(sources "src/main.cpp"
|
|||
"src/WorldUndoManager.cpp"
|
||||
"src/GUIHolder.cpp"
|
||||
"src/GlobalConfig.cpp"
|
||||
"src/RichTextUserInput.cpp"
|
||||
"src/Bookmarks/BookmarkListItem.cpp"
|
||||
"src/Bookmarks/BookmarkManager.cpp"
|
||||
"src/ResourceDisplay/ResourceDisplay.cpp"
|
||||
|
|
|
|||
|
|
@ -207,22 +207,22 @@ void TextBoxEditTool::right_click_popup_gui(CanvasComponentContainer::ObjInfo* c
|
|||
gui.element<PositionAdjustingPopupMenu>("Text popup menu", popupPos, [&, popupPos] {
|
||||
text_label_light(gui, "Text menu");
|
||||
InputManager& input = drawP.world.main.input;
|
||||
drawP.popup_menu_action_button("Paste", "Paste", [&] {
|
||||
input.call_text_paste(true);
|
||||
});
|
||||
drawP.popup_menu_action_button("Paste without formatting", "Paste without formatting", [&] {
|
||||
input.call_text_paste(false);
|
||||
});
|
||||
if(a.cursor->selectionBeginPos != a.cursor->selectionEndPos) {
|
||||
drawP.popup_menu_action_button("Copy", "Copy", [&] {
|
||||
input.set_clipboard_plain_and_richtext_pair(a.textBox->process_copy(*a.cursor));
|
||||
});
|
||||
drawP.popup_menu_action_button("Cut", "Cut", [&] {
|
||||
input.text.do_textbox_operation_with_undo([&]() {
|
||||
input.set_clipboard_plain_and_richtext_pair(a.textBox->process_cut(*a.cursor));
|
||||
});
|
||||
});
|
||||
}
|
||||
//drawP.popup_menu_action_button("Paste", "Paste", [&] {
|
||||
// input.call_text_paste(true);
|
||||
//});
|
||||
//drawP.popup_menu_action_button("Paste without formatting", "Paste without formatting", [&] {
|
||||
// input.call_text_paste(false);
|
||||
//});
|
||||
//if(a.cursor->selectionBeginPos != a.cursor->selectionEndPos) {
|
||||
// drawP.popup_menu_action_button("Copy", "Copy", [&] {
|
||||
// input.set_clipboard_plain_and_richtext_pair(a.textBox->process_copy(*a.cursor));
|
||||
// });
|
||||
// drawP.popup_menu_action_button("Cut", "Cut", [&] {
|
||||
// input.text.do_textbox_operation_with_undo([&]() {
|
||||
// input.set_clipboard_plain_and_richtext_pair(a.textBox->process_cut(*a.cursor));
|
||||
// });
|
||||
// });
|
||||
//}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -242,7 +242,7 @@ void TextBoxEditTool::release_undo_data(const std::string& undoName) {
|
|||
if(it != undoHeldData.end()) {
|
||||
std::pair<RichText::TextBox::Cursor, RichText::TextData>& undoData = it->second;
|
||||
InputManager& input = drawP.world.main.input;
|
||||
input.text.add_textbox_undo(undoData.first, undoData.second);
|
||||
//input.text.add_textbox_undo(undoData.first, undoData.second);
|
||||
undoHeldData.erase(it);
|
||||
}
|
||||
}
|
||||
|
|
@ -252,13 +252,13 @@ void TextBoxEditTool::add_undo_if_selecting_area(TextBoxCanvasComponent& a, cons
|
|||
func();
|
||||
else {
|
||||
InputManager& input = drawP.world.main.input;
|
||||
input.text.do_textbox_operation_with_undo(func);
|
||||
//input.text.do_textbox_operation_with_undo(func);
|
||||
}
|
||||
}
|
||||
|
||||
void TextBoxEditTool::add_undo(const std::function<void()>& func) {
|
||||
InputManager& input = drawP.world.main.input;
|
||||
input.text.do_textbox_operation_with_undo(func);
|
||||
//input.text.do_textbox_operation_with_undo(func);
|
||||
}
|
||||
|
||||
uint8_t TextBoxEditTool::get_new_decoration_value() {
|
||||
|
|
@ -299,7 +299,7 @@ void TextBoxEditTool::commit_edit_updates(CanvasComponentContainer::ObjInfo* com
|
|||
auto& a = static_cast<TextBoxCanvasComponent&>(comp->obj->get_comp());
|
||||
a.d.editing = false;
|
||||
comp->obj->commit_update(drawP);
|
||||
drawP.world.main.input.remove_rich_text_box_input(a.textBox);
|
||||
//drawP.world.main.input.remove_rich_text_box_input(a.textBox);
|
||||
}
|
||||
|
||||
TextBoxEditTool::TextBoxEditToolAllData TextBoxEditTool::get_all_data(const TextBoxCanvasComponent& a) {
|
||||
|
|
@ -330,13 +330,13 @@ void TextBoxEditTool::edit_start(EditTool& editTool, CanvasComponentContainer::O
|
|||
|
||||
comp->obj->commit_update(drawP);
|
||||
|
||||
drawP.world.main.input.set_rich_text_box_input_back(a.textBox, a.cursor, true, nullptr, {
|
||||
.inputType = SDL_TextInputType::SDL_TEXTINPUT_TYPE_TEXT,
|
||||
.capitalization = SDL_Capitalization::SDL_CAPITALIZE_NONE,
|
||||
.autocorrect = true,
|
||||
.multiline = true,
|
||||
.androidInputType = InputManager::AndroidInputType::ANDROIDTEXT_TYPE_CLASS_TEXT
|
||||
}, currentModsPtr);
|
||||
//drawP.world.main.input.set_rich_text_box_input_back(a.textBox, a.cursor, true, nullptr, {
|
||||
// .inputType = SDL_TextInputType::SDL_TEXTINPUT_TYPE_TEXT,
|
||||
// .capitalization = SDL_Capitalization::SDL_CAPITALIZE_NONE,
|
||||
// .autocorrect = true,
|
||||
// .multiline = true,
|
||||
// .androidInputType = InputManager::AndroidInputType::ANDROIDTEXT_TYPE_CLASS_TEXT
|
||||
//}, currentModsPtr);
|
||||
}
|
||||
|
||||
bool TextBoxEditTool::edit_update(CanvasComponentContainer::ObjInfo* comp) {
|
||||
|
|
|
|||
|
|
@ -119,6 +119,14 @@ void GUIHolder::draw(SkCanvas* canvas, bool skiaAA) {
|
|||
canvas->restore();
|
||||
}
|
||||
|
||||
void GUIHolder::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {
|
||||
gui.input_text_key_callback(key);
|
||||
}
|
||||
|
||||
void GUIHolder::input_text_callback(const std::string& str) {
|
||||
gui.input_text_callback(str);
|
||||
}
|
||||
|
||||
void GUIHolder::input_key_callback(const InputManager::KeyCallbackArgs& key) {
|
||||
gui.input_key_callback(key);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ class GUIHolder {
|
|||
|
||||
void update();
|
||||
void draw(SkCanvas* canvas, bool skiaAA);
|
||||
|
||||
void input_text_key_callback(const InputManager::KeyCallbackArgs& key);
|
||||
void input_text_callback(const std::string& str);
|
||||
void input_key_callback(const InputManager::KeyCallbackArgs& key);
|
||||
void input_text_key_callback();
|
||||
void input_text_input_callback();
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ namespace GUIStuff {
|
|||
|
||||
void Element::tick_update() {}
|
||||
|
||||
void Element::input_text_key_callback(const InputManager::KeyCallbackArgs& key) { }
|
||||
void Element::input_text_callback(const std::string& str) { }
|
||||
void Element::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) { }
|
||||
void Element::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) { }
|
||||
void Element::input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel) { }
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ namespace GUIStuff {
|
|||
virtual void tick_update();
|
||||
|
||||
// Return true when mouse obstructs what's behind it
|
||||
virtual void input_text_key_callback(const InputManager::KeyCallbackArgs& key);
|
||||
virtual void input_text_callback(const std::string& str);
|
||||
virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button);
|
||||
virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion);
|
||||
virtual void input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <modules/skparagraph/include/TextStyle.h>
|
||||
#include "../../FontData.hpp"
|
||||
#include "../../InputManager.hpp"
|
||||
#include "../../RichTextUserInput.hpp"
|
||||
|
||||
namespace GUIStuff {
|
||||
|
||||
|
|
@ -20,27 +21,39 @@ template <typename T> struct TextBoxData {
|
|||
std::function<void()> onEnter;
|
||||
};
|
||||
|
||||
|
||||
struct TextEditData {
|
||||
TextEditData(unsigned initTextboxInputID, const std::shared_ptr<RichText::TextBox>& initTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& initCursor, const std::function<void()>& onTextEdit):
|
||||
textboxInputID(initTextboxInputID),
|
||||
userInput(initTextBox, initCursor, nullptr, onTextEdit)
|
||||
{}
|
||||
unsigned textboxInputID;
|
||||
RichTextUserInput userInput;
|
||||
};
|
||||
|
||||
template <typename T> class TextBox : public Element {
|
||||
public:
|
||||
TextBox(GUIManager& gui);
|
||||
|
||||
void layout(const Clay_ElementId& id, const TextBoxData<T>& userInfo);
|
||||
virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override;
|
||||
virtual void input_text_key_callback(const InputManager::KeyCallbackArgs& key) override;
|
||||
virtual void input_text_callback(const std::string& str) override;
|
||||
virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override;
|
||||
virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override;
|
||||
virtual void input_key_callback(const InputManager::KeyCallbackArgs& key) override;
|
||||
~TextBox();
|
||||
private:
|
||||
void init_textbox(UpdateInputData& io);
|
||||
void reset_textbox_text();
|
||||
bool update_data();
|
||||
bool is_selected() const;
|
||||
|
||||
std::optional<TextEditData> edit;
|
||||
|
||||
std::optional<T> oldData;
|
||||
bool isSelected = false;
|
||||
TextBoxData<T> userInfo;
|
||||
std::shared_ptr<RichText::TextBox> textbox;
|
||||
std::shared_ptr<RichText::TextBox::Cursor> cur;
|
||||
std::shared_ptr<SCollision::AABB<float>> rect;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ template <typename T> void TextBox<T>::clay_draw(SkCanvas* canvas, UpdateInputDa
|
|||
SkRect r = SkRect::MakeXYWH(bb.min.x(), bb.min.y(), bb.width(), bb.height());
|
||||
|
||||
canvas->drawRect(r, SkPaint(io.theme->backColor2));
|
||||
SkPaint outline(isSelected ? io.theme->fillColor1 : io.theme->backColor2);
|
||||
SkPaint outline(is_selected() ? io.theme->fillColor1 : io.theme->backColor2);
|
||||
outline.setStroke(true);
|
||||
outline.setStrokeWidth(2.0f);
|
||||
outline.setAntiAlias(skiaAA);
|
||||
|
|
@ -40,7 +40,7 @@ template <typename T> void TextBox<T>::clay_draw(SkCanvas* canvas, UpdateInputDa
|
|||
yOffset -= textbox->get_height() * 0.5f;
|
||||
|
||||
RichText::TextBox::PaintOpts paintOpts;
|
||||
if(isSelected) {
|
||||
if(is_selected()) {
|
||||
paintOpts.cursor = *cur;
|
||||
SkRect cursorRect = textbox->get_cursor_rect(cur->pos);
|
||||
canvas->translate(bb.min.x() - std::max(cursorRect.fRight - bb.width(), -2.0f), bb.min.y() + yOffset);
|
||||
|
|
@ -61,45 +61,65 @@ template <typename T> void TextBox<T>::clay_draw(SkCanvas* canvas, UpdateInputDa
|
|||
canvas->restore();
|
||||
}
|
||||
|
||||
template <typename T> bool TextBox<T>::is_selected() const {
|
||||
return edit.has_value();
|
||||
}
|
||||
|
||||
template <typename T> void TextBox<T>::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {
|
||||
if(is_selected()) {
|
||||
if(key.key == InputManager::KEY_GENERIC_ENTER && key.down) {
|
||||
bool success = update_data();
|
||||
gui.set_post_callback_func_high_priority([&, success] {
|
||||
if(success && userInfo.onEdit) userInfo.onEdit();
|
||||
if(userInfo.onEnter) userInfo.onEnter();
|
||||
reset_textbox_text();
|
||||
});
|
||||
}
|
||||
else
|
||||
edit.value().userInput.input_key_callback(*gui.io.input, key);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void TextBox<T>::input_text_callback(const std::string& str) {
|
||||
if(is_selected())
|
||||
edit.value().userInput.add_text_to_textbox(str);
|
||||
}
|
||||
|
||||
template <typename T> void TextBox<T>::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {
|
||||
auto& io = gui.io;
|
||||
|
||||
if(button.button == InputManager::MouseButton::LEFT && boundingBox.has_value()) {
|
||||
if(button.down) {
|
||||
if(mouseHovering) {
|
||||
*rect = {(boundingBox.value().min + io.windowPos) * io.guiScaleMultiplier, (boundingBox.value().max + io.windowPos) * io.guiScaleMultiplier};
|
||||
gui.io.input->set_rich_text_box_input_front(textbox, cur, false, rect, userInfo.textInputProps, nullptr);
|
||||
textbox->process_mouse_left_button(*cur, button.pos - boundingBox.value().min, button.clicks, true, gui.io.input->key(InputManager::KEY_TEXT_SHIFT).held);
|
||||
isSelected = true;
|
||||
SCollision::AABB<float> rect = {(boundingBox.value().min + io.windowPos) * io.guiScaleMultiplier, (boundingBox.value().max + io.windowPos) * io.guiScaleMultiplier};
|
||||
unsigned id = gui.io.input->set_text_box_front(rect, userInfo.textInputProps);
|
||||
textbox->process_mouse_left_button(*cur, button.pos - boundingBox.value().min, button.clicks, true, gui.io.input->key(InputManager::KEY_GENERIC_LSHIFT).held);
|
||||
edit = TextEditData(id, textbox, cur, [&] {
|
||||
if(userInfo.immutable)
|
||||
cur->pos = cur->selectionBeginPos = cur->selectionEndPos = textbox->insert({0, 0}, userInfo.toStr(*userInfo.data));
|
||||
else {
|
||||
if(update_data() && userInfo.onEdit)
|
||||
gui.set_post_callback_func_high_priority(userInfo.onEdit);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(isSelected) {
|
||||
gui.io.input->remove_rich_text_box_input(textbox);
|
||||
else if(is_selected()) {
|
||||
gui.io.input->remove_text_box(edit.value().textboxInputID);
|
||||
if(update_data())
|
||||
gui.set_post_callback_func_high_priority(userInfo.onEdit);
|
||||
reset_textbox_text();
|
||||
isSelected = false;
|
||||
edit = std::nullopt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
textbox->process_mouse_left_button(*cur, button.pos - boundingBox.value().min, 0, false, gui.io.input->key(InputManager::KEY_TEXT_SHIFT).held);
|
||||
textbox->process_mouse_left_button(*cur, button.pos - boundingBox.value().min, 0, false, gui.io.input->key(InputManager::KEY_GENERIC_LSHIFT).held);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void TextBox<T>::input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) {
|
||||
if(boundingBox.has_value())
|
||||
textbox->process_mouse_left_button(*cur, motion.pos - boundingBox.value().min, 0, gui.io.input->mouse.leftDown, gui.io.input->key(InputManager::KEY_TEXT_SHIFT).held);
|
||||
}
|
||||
|
||||
template <typename T> void TextBox<T>::input_key_callback(const InputManager::KeyCallbackArgs& key) {
|
||||
if(key.key == InputManager::KEY_TEXT_ENTER && key.down && isSelected) {
|
||||
bool success = update_data();
|
||||
gui.set_post_callback_func_high_priority([&, success] {
|
||||
if(success && userInfo.onEdit) userInfo.onEdit();
|
||||
if(userInfo.onEnter) userInfo.onEnter();
|
||||
reset_textbox_text();
|
||||
});
|
||||
}
|
||||
textbox->process_mouse_left_button(*cur, motion.pos - boundingBox.value().min, 0, gui.io.input->mouse.leftDown, gui.io.input->key(InputManager::KEY_GENERIC_LSHIFT).held);
|
||||
}
|
||||
|
||||
template <typename T> void TextBox<T>::init_textbox(UpdateInputData& io) {
|
||||
|
|
@ -109,17 +129,7 @@ template <typename T> void TextBox<T>::init_textbox(UpdateInputData& io) {
|
|||
textbox->set_font_data(io.fonts);
|
||||
textbox->set_allow_newlines(false);
|
||||
cur = std::make_shared<RichText::TextBox::Cursor>();
|
||||
rect = std::make_shared<SCollision::AABB<float>>();
|
||||
}
|
||||
|
||||
textbox->onUserTextEdit = [&] {
|
||||
if(userInfo.immutable)
|
||||
cur->pos = cur->selectionBeginPos = cur->selectionEndPos = textbox->insert({0, 0}, userInfo.toStr(*userInfo.data));
|
||||
else {
|
||||
if(update_data() && userInfo.onEdit)
|
||||
gui.set_post_callback_func_high_priority(userInfo.onEdit);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T> void TextBox<T>::reset_textbox_text() {
|
||||
|
|
@ -138,7 +148,8 @@ template <typename T> bool TextBox<T>::update_data() {
|
|||
}
|
||||
|
||||
template <typename T> TextBox<T>::~TextBox() {
|
||||
gui.io.input->remove_rich_text_box_input(textbox);
|
||||
if(is_selected())
|
||||
gui.io.input->remove_text_box(edit.value().textboxInputID);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -344,6 +344,20 @@ bool GUIManager::cursor_obstructed() const {
|
|||
return cursorObstructed;
|
||||
}
|
||||
|
||||
void GUIManager::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {
|
||||
for(ElementContainer* e : orderedElements)
|
||||
e->elem->input_text_key_callback(key);
|
||||
run_post_callback_func();
|
||||
layout_if_necessary();
|
||||
}
|
||||
|
||||
void GUIManager::input_text_callback(const std::string& str) {
|
||||
for(ElementContainer* e : orderedElements)
|
||||
e->elem->input_text_callback(str);
|
||||
run_post_callback_func();
|
||||
layout_if_necessary();
|
||||
}
|
||||
|
||||
void GUIManager::input_key_callback(const InputManager::KeyCallbackArgs& key) {
|
||||
for(ElementContainer* e : orderedElements)
|
||||
e->elem->input_key_callback(key);
|
||||
|
|
|
|||
|
|
@ -85,6 +85,8 @@ class GUIManager {
|
|||
|
||||
DefaultStringArena strArena;
|
||||
|
||||
void input_text_key_callback(const InputManager::KeyCallbackArgs& key);
|
||||
void input_text_callback(const std::string& str);
|
||||
void input_key_callback(const InputManager::KeyCallbackArgs& key);
|
||||
void input_mouse_button_callback(InputManager::MouseButtonCallbackArgs button);
|
||||
void input_mouse_motion_callback(InputManager::MouseMotionCallbackArgs motion);
|
||||
|
|
|
|||
|
|
@ -30,13 +30,6 @@ extern "C" {
|
|||
|
||||
#include "MainProgram.hpp"
|
||||
|
||||
template <typename T> std::optional<T> shared_ptr_to_opt(const std::shared_ptr<T> o) {
|
||||
if(o)
|
||||
return *o;
|
||||
else
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
InputManager::InputManager(MainProgram& initMain):
|
||||
main(initMain) {
|
||||
frame_reset({0, 0});
|
||||
|
|
@ -95,75 +88,40 @@ InputManager::InputManager(MainProgram& initMain):
|
|||
keyAssignments = defaultKeyAssignments;
|
||||
}
|
||||
|
||||
void InputManager::set_rich_text_box_input_front(const std::shared_ptr<RichText::TextBox>& nTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& nCursor, bool isRichTextBox, const std::shared_ptr<SCollision::AABB<float>>& textboxRect, const TextInputProperties& inputProps, const std::shared_ptr<RichText::TextStyleModifier::ModifierMap>& nModMap) {
|
||||
unsigned InputManager::Text::get_id() {
|
||||
static unsigned nextID = 0;
|
||||
while(std::find_if(textBoxes.begin(), textBoxes.end(), [&](const TextBoxInfo& info) { return info.id == nextID; }) != textBoxes.end())
|
||||
++nextID;
|
||||
return nextID;
|
||||
}
|
||||
|
||||
unsigned InputManager::set_text_box_front(const std::optional<SCollision::AABB<float>>& textboxRect, const TextInputProperties& inputProps) {
|
||||
Text::TextBoxInfo textBoxInfo;
|
||||
textBoxInfo.textBox = nTextBox;
|
||||
textBoxInfo.cursor = nCursor;
|
||||
textBoxInfo.modMap = nModMap;
|
||||
textBoxInfo.isRichTextBox = isRichTextBox;
|
||||
textBoxInfo.rect = textboxRect;
|
||||
textBoxInfo.textInputProperties = inputProps;
|
||||
textBoxInfo.id = text.get_id();
|
||||
text.textBoxes.emplace_front(textBoxInfo);
|
||||
text.update_accepting_input(main.window.sdlWindow);
|
||||
return textBoxInfo.id;
|
||||
}
|
||||
|
||||
void InputManager::set_rich_text_box_input_back(const std::shared_ptr<RichText::TextBox>& nTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& nCursor, bool isRichTextBox, const std::shared_ptr<SCollision::AABB<float>>& textboxRect, const TextInputProperties& inputProps, const std::shared_ptr<RichText::TextStyleModifier::ModifierMap>& nModMap) {
|
||||
unsigned InputManager::set_text_box_back(const std::optional<SCollision::AABB<float>>& textboxRect, const TextInputProperties& inputProps) {
|
||||
Text::TextBoxInfo textBoxInfo;
|
||||
textBoxInfo.textBox = nTextBox;
|
||||
textBoxInfo.cursor = nCursor;
|
||||
textBoxInfo.modMap = nModMap;
|
||||
textBoxInfo.isRichTextBox = isRichTextBox;
|
||||
textBoxInfo.rect = textboxRect;
|
||||
textBoxInfo.textInputProperties = inputProps;
|
||||
textBoxInfo.id = text.get_id();
|
||||
text.textBoxes.emplace_back(textBoxInfo);
|
||||
text.update_accepting_input(main.window.sdlWindow);
|
||||
return textBoxInfo.id;
|
||||
}
|
||||
|
||||
void InputManager::remove_rich_text_box_input(const std::shared_ptr<RichText::TextBox>& nTextBox) {
|
||||
std::erase_if(text.textBoxes, [&nTextBox](Text::TextBoxInfo& info) {
|
||||
return (info.textBox == nTextBox);
|
||||
void InputManager::remove_text_box(unsigned id) {
|
||||
std::erase_if(text.textBoxes, [id](Text::TextBoxInfo& info) {
|
||||
return (info.id == id);
|
||||
});
|
||||
text.update_accepting_input(main.window.sdlWindow);
|
||||
}
|
||||
|
||||
void InputManager::add_text_to_textbox(const std::string& inputText) {
|
||||
if(!text.textBoxes.empty() && !inputText.empty()) {
|
||||
auto& frontTextBox = text.textBoxes.front();
|
||||
text.do_textbox_operation_with_undo([&]() {
|
||||
frontTextBox.textBox->process_text_input(*frontTextBox.cursor, inputText, shared_ptr_to_opt(frontTextBox.modMap));
|
||||
});
|
||||
main.input_text_input_callback();
|
||||
}
|
||||
}
|
||||
|
||||
void InputManager::Text::add_textbox_undo(const RichText::TextBox::Cursor& prevCursor, const RichText::TextData& prevRichText) {
|
||||
if(!textBoxes.empty()) {
|
||||
auto& frontTextBox = textBoxes.front();
|
||||
frontTextBox.textboxUndo.push({[textBox = frontTextBox.textBox, cursor = frontTextBox.cursor, prevCursor = prevCursor, prevRichText = prevRichText]() {
|
||||
textBox->set_rich_text_data_for_undo_redo(prevRichText);
|
||||
cursor->selectionBeginPos = cursor->selectionEndPos = cursor->pos = std::max(prevCursor.selectionEndPos, prevCursor.selectionBeginPos);
|
||||
cursor->previousX = std::nullopt;
|
||||
return true;
|
||||
},
|
||||
[textBox = frontTextBox.textBox, cursor = frontTextBox.cursor, currentCursor = *frontTextBox.cursor, currentRichText = frontTextBox.textBox->get_rich_text_data()]() {
|
||||
textBox->set_rich_text_data_for_undo_redo(currentRichText);
|
||||
cursor->selectionBeginPos = cursor->selectionEndPos = cursor->pos = std::max(currentCursor.selectionEndPos, currentCursor.selectionBeginPos);
|
||||
cursor->previousX = std::nullopt;
|
||||
return true;
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
void InputManager::Text::do_textbox_operation_with_undo(const std::function<void()>& func) {
|
||||
if(!textBoxes.empty()) {
|
||||
auto& frontTextBox = textBoxes.front();
|
||||
auto prevRichText = frontTextBox.textBox->get_rich_text_data();
|
||||
auto prevCursor = *frontTextBox.cursor;
|
||||
func();
|
||||
add_textbox_undo(prevCursor, prevRichText);
|
||||
}
|
||||
}
|
||||
|
||||
bool InputManager::Text::is_accepting_input() {
|
||||
return !textBoxes.empty();
|
||||
}
|
||||
|
|
@ -369,10 +327,18 @@ const InputManager::KeyData& InputManager::key(KeyCode kCode) {
|
|||
void InputManager::set_key_down(const SDL_KeyboardEvent& e, KeyCode kCode) {
|
||||
auto& k = keys[kCode];
|
||||
k.held = true;
|
||||
if(text.is_accepting_input())
|
||||
main.input_text_key_callback(KeyCallbackArgs{.key = kCode, .down = e.down, .repeat = e.repeat});
|
||||
else
|
||||
main.input_key_callback(KeyCallbackArgs{.key = kCode, .down = e.down, .repeat = e.repeat});
|
||||
}
|
||||
|
||||
void InputManager::set_key_up(const SDL_KeyboardEvent& e, KeyCode kCode) {
|
||||
keys[kCode].held = false;
|
||||
if(text.is_accepting_input())
|
||||
main.input_text_key_callback(KeyCallbackArgs{.key = kCode, .down = e.down, .repeat = e.repeat});
|
||||
// Send key up even if text input is happening
|
||||
main.input_key_callback(KeyCallbackArgs{.key = kCode, .down = e.down, .repeat = e.repeat});
|
||||
}
|
||||
|
||||
uint32_t InputManager::make_generic_key_mod(SDL_Keymod m) {
|
||||
|
|
@ -388,6 +354,10 @@ uint32_t InputManager::make_generic_key_mod(SDL_Keymod m) {
|
|||
return toRet;
|
||||
}
|
||||
|
||||
void InputManager::backend_input_text_event(const std::string& str) {
|
||||
main.input_text_callback(str);
|
||||
}
|
||||
|
||||
void InputManager::backend_drop_file_event(const SDL_DropEvent& e) {
|
||||
Vector2f mousePos = {e.x * main.window.density, e.y * main.window.density};
|
||||
mouse.set_pos(mousePos);
|
||||
|
|
@ -851,184 +821,89 @@ void InputManager::backend_key_down_update(const SDL_KeyboardEvent& e) {
|
|||
return;
|
||||
}
|
||||
|
||||
// e.key != SDLK_LMETA && e.key != SDLK_RMETA &&
|
||||
|
||||
std::shared_ptr<RichText::TextBox> textBox = text.textBoxes.empty() ? nullptr : text.textBoxes.front().textBox;
|
||||
std::shared_ptr<RichText::TextBox::Cursor> cursor = text.textBoxes.empty() ? nullptr : text.textBoxes.front().cursor;
|
||||
std::optional<RichText::TextStyleModifier::ModifierMap> modMap = text.textBoxes.empty() ? std::nullopt : shared_ptr_to_opt(text.textBoxes.front().modMap);
|
||||
|
||||
switch(kPress) {
|
||||
case SDLK_UP:
|
||||
set_key_down(e, KEY_TEXT_UP);
|
||||
if(textBox)
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::UP, ctrl_or_meta_held(), key(KEY_GENERIC_LSHIFT).held, modMap);
|
||||
set_key_down(e, KEY_GENERIC_UP);
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
set_key_down(e, KEY_TEXT_DOWN);
|
||||
if(textBox)
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::DOWN, ctrl_or_meta_held(), key(KEY_GENERIC_LSHIFT).held, modMap);
|
||||
set_key_down(e, KEY_GENERIC_DOWN);
|
||||
break;
|
||||
case SDLK_LEFT:
|
||||
set_key_down(e, KEY_TEXT_LEFT);
|
||||
if(textBox)
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::LEFT, ctrl_or_meta_held(), key(KEY_GENERIC_LSHIFT).held, modMap);
|
||||
set_key_down(e, KEY_GENERIC_LEFT);
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
set_key_down(e, KEY_TEXT_RIGHT);
|
||||
if(textBox)
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::RIGHT, ctrl_or_meta_held(), key(KEY_GENERIC_LSHIFT).held, modMap);
|
||||
set_key_down(e, KEY_GENERIC_RIGHT);
|
||||
break;
|
||||
case SDLK_BACKSPACE:
|
||||
set_key_down(e, KEY_TEXT_BACKSPACE);
|
||||
if(textBox)
|
||||
text.do_textbox_operation_with_undo([&]() {
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::BACKSPACE, ctrl_or_meta_held(), key(KEY_GENERIC_LSHIFT).held, modMap);
|
||||
});
|
||||
break;
|
||||
case SDLK_DELETE:
|
||||
set_key_down(e, KEY_TEXT_DELETE);
|
||||
if(textBox)
|
||||
text.do_textbox_operation_with_undo([&]() {
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::DEL, ctrl_or_meta_held(), key(KEY_GENERIC_LSHIFT).held, modMap);
|
||||
});
|
||||
break;
|
||||
case SDLK_HOME:
|
||||
set_key_down(e, KEY_TEXT_HOME);
|
||||
if(textBox)
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::HOME, ctrl_or_meta_held(), key(KEY_GENERIC_LSHIFT).held, modMap);
|
||||
break;
|
||||
case SDLK_END:
|
||||
set_key_down(e, KEY_TEXT_END);
|
||||
if(textBox)
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::END, ctrl_or_meta_held(), key(KEY_GENERIC_LSHIFT).held, modMap);
|
||||
break;
|
||||
case SDLK_LSHIFT:
|
||||
set_key_down(e, KEY_TEXT_SHIFT);
|
||||
set_key_down(e, KEY_GENERIC_LSHIFT);
|
||||
break;
|
||||
case SDLK_LALT:
|
||||
set_key_down(e, KEY_GENERIC_LALT);
|
||||
break;
|
||||
case SDLK_LCTRL:
|
||||
set_key_down(e, KEY_TEXT_CTRL);
|
||||
set_key_down(e, KEY_GENERIC_LCTRL);
|
||||
break;
|
||||
case SDLK_LMETA:
|
||||
set_key_down(e, KEY_TEXT_META);
|
||||
set_key_down(e, KEY_GENERIC_LMETA);
|
||||
break;
|
||||
case SDLK_C:
|
||||
// Use either Ctrl or Meta (command for Mac) keys. We do either instead of checking, since checking can get complicated on Emscripten
|
||||
if((kMod & SDL_KMOD_GUI) || (kMod & SDL_KMOD_CTRL)) {
|
||||
if((kMod & SDL_KMOD_GUI) || (kMod & SDL_KMOD_CTRL))
|
||||
set_key_down(e, KEY_TEXT_COPY);
|
||||
if(textBox)
|
||||
set_clipboard_plain_and_richtext_pair(textBox->process_copy(*cursor));
|
||||
}
|
||||
break;
|
||||
case SDLK_X:
|
||||
if((kMod & SDL_KMOD_GUI) || (kMod & SDL_KMOD_CTRL)) {
|
||||
if((kMod & SDL_KMOD_GUI) || (kMod & SDL_KMOD_CTRL))
|
||||
set_key_down(e, KEY_TEXT_CUT);
|
||||
if(textBox)
|
||||
text.do_textbox_operation_with_undo([&]() {
|
||||
set_clipboard_plain_and_richtext_pair(textBox->process_cut(*cursor));
|
||||
});
|
||||
}
|
||||
break;
|
||||
case SDLK_V:
|
||||
if((kMod & SDL_KMOD_GUI) || (kMod & SDL_KMOD_CTRL)) {
|
||||
if((kMod & SDL_KMOD_GUI) || (kMod & SDL_KMOD_CTRL))
|
||||
set_key_down(e, KEY_TEXT_PASTE);
|
||||
if(textBox)
|
||||
text.do_textbox_operation_with_undo([&]() {
|
||||
call_text_paste(true);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case SDLK_A:
|
||||
if((kMod & SDL_KMOD_GUI) || (kMod & SDL_KMOD_CTRL)) {
|
||||
if((kMod & SDL_KMOD_GUI) || (kMod & SDL_KMOD_CTRL))
|
||||
set_key_down(e, KEY_TEXT_SELECTALL);
|
||||
if(textBox)
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::SELECT_ALL, ctrl_or_meta_held(), key(KEY_GENERIC_LSHIFT).held, modMap);
|
||||
}
|
||||
break;
|
||||
case SDLK_Z:
|
||||
if((kMod & SDL_KMOD_GUI) || (kMod & SDL_KMOD_CTRL)) {
|
||||
if((kMod & SDL_KMOD_GUI) || (kMod & SDL_KMOD_CTRL))
|
||||
set_key_down(e, KEY_TEXT_UNDO);
|
||||
if(textBox)
|
||||
text.textBoxes.front().textboxUndo.undo();
|
||||
}
|
||||
break;
|
||||
case SDLK_R:
|
||||
if((kMod & SDL_KMOD_GUI) || (kMod & SDL_KMOD_CTRL)) {
|
||||
if((kMod & SDL_KMOD_GUI) || (kMod & SDL_KMOD_CTRL))
|
||||
set_key_down(e, KEY_TEXT_REDO);
|
||||
if(textBox)
|
||||
text.textBoxes.front().textboxUndo.redo();
|
||||
}
|
||||
break;
|
||||
case SDLK_RETURN: {
|
||||
set_key_down(e, KEY_TEXT_ENTER);
|
||||
if(textBox)
|
||||
text.do_textbox_operation_with_undo([&]() {
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::ENTER, ctrl_or_meta_held(), key(KEY_GENERIC_LSHIFT).held, modMap);
|
||||
});
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_ENTER, .down = e.down, .repeat = e.repeat});
|
||||
case SDLK_RETURN:
|
||||
set_key_down(e, KEY_GENERIC_ENTER);
|
||||
break;
|
||||
}
|
||||
case SDLK_TAB: {
|
||||
case SDLK_TAB:
|
||||
set_key_down(e, KEY_TEXT_TAB);
|
||||
if(textBox)
|
||||
text.do_textbox_operation_with_undo([&]() {
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::TAB, ctrl_or_meta_held(), key(KEY_GENERIC_LSHIFT).held, modMap);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case SDLK_ESCAPE:
|
||||
set_key_down(e, KEY_TEXT_ESCAPE);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_ESCAPE, .down = e.down, .repeat = e.repeat});
|
||||
set_key_down(e, KEY_GENERIC_ESCAPE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(text.is_accepting_input()) {
|
||||
main.input_text_key_callback();
|
||||
return;
|
||||
}
|
||||
|
||||
auto f = keyAssignments.find({make_generic_key_mod(kMod), kPress});
|
||||
if(f != keyAssignments.end()) {
|
||||
if(f != keyAssignments.end())
|
||||
set_key_down(e, f->second);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = f->second, .down = e.down, .repeat = e.repeat});
|
||||
}
|
||||
switch(kPress) {
|
||||
case SDLK_UP:
|
||||
set_key_down(e, KEY_GENERIC_UP);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_UP, .down = e.down, .repeat = e.repeat});
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
set_key_down(e, KEY_GENERIC_DOWN);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_DOWN, .down = e.down, .repeat = e.repeat});
|
||||
break;
|
||||
case SDLK_LEFT:
|
||||
set_key_down(e, KEY_GENERIC_LEFT);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_LEFT, .down = e.down, .repeat = e.repeat});
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
set_key_down(e, KEY_GENERIC_RIGHT);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_RIGHT, .down = e.down, .repeat = e.repeat});
|
||||
break;
|
||||
case SDLK_RETURN:
|
||||
set_key_down(e, KEY_GENERIC_ENTER);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_ENTER, .down = e.down, .repeat = e.repeat});
|
||||
break;
|
||||
case SDLK_ESCAPE:
|
||||
set_key_down(e, KEY_GENERIC_ESCAPE);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_ESCAPE, .down = e.down, .repeat = e.repeat});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void InputManager::call_text_paste(bool isRichTextPaste) {
|
||||
text.isNextPasteRich = isRichTextPaste;
|
||||
void InputManager::call_text_paste(const std::function<void(const TextPasteCallbackArgs&)>& pasteCallbackFunc) {
|
||||
// Workaround for not being able to copy richtext to system clipboard, this should at least work within the application itself
|
||||
pasteCallback = pasteCallbackFunc;
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_browser_clipboard::paste_async([](std::string&& pasteData, void* callbackData){
|
||||
InputManager* inMan = (InputManager*)callbackData;
|
||||
|
|
@ -1040,17 +915,12 @@ void InputManager::call_text_paste(bool isRichTextPaste) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void InputManager::process_text_paste(const std::string& plainClipboardStr) {
|
||||
if(!text.textBoxes.empty()) {
|
||||
// Workaround for not being able to copy richtext to system clipboard, this should at least work within the application itself
|
||||
if(text.textBoxes.front().isRichTextBox && text.isNextPasteRich && lastCopiedRichText.has_value()) {
|
||||
if(lastCopiedRichText.value().get_plain_text() == remove_carriage_returns_from_str(plainClipboardStr))
|
||||
text.textBoxes.front().textBox->process_rich_text_input(*text.textBoxes.front().cursor, lastCopiedRichText.value());
|
||||
else
|
||||
text.textBoxes.front().textBox->process_text_input(*text.textBoxes.front().cursor, plainClipboardStr, shared_ptr_to_opt(text.textBoxes.front().modMap));
|
||||
}
|
||||
else
|
||||
text.textBoxes.front().textBox->process_text_input(*text.textBoxes.front().cursor, plainClipboardStr, shared_ptr_to_opt(text.textBoxes.front().modMap));
|
||||
void InputManager::process_text_paste(const std::string& pasteStr) {
|
||||
if(lastCopiedRichText.has_value() && lastCopiedRichText.value().get_plain_text() == remove_carriage_returns_from_str(pasteStr)) {
|
||||
pasteCallback({
|
||||
.text = pasteStr,
|
||||
.richText = lastCopiedRichText
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1060,20 +930,19 @@ bool InputManager::ctrl_or_meta_held() {
|
|||
|
||||
void InputManager::backend_key_up_update(const SDL_KeyboardEvent& e) {
|
||||
auto kPress = e.key;
|
||||
//auto kMod = e.mod;
|
||||
|
||||
switch(kPress) {
|
||||
case SDLK_UP:
|
||||
set_key_up(e, KEY_TEXT_UP);
|
||||
set_key_up(e, KEY_GENERIC_UP);
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
set_key_up(e, KEY_TEXT_DOWN);
|
||||
set_key_up(e, KEY_GENERIC_DOWN);
|
||||
break;
|
||||
case SDLK_LEFT:
|
||||
set_key_up(e, KEY_TEXT_LEFT);
|
||||
set_key_up(e, KEY_GENERIC_LEFT);
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
set_key_up(e, KEY_TEXT_RIGHT);
|
||||
set_key_up(e, KEY_GENERIC_RIGHT);
|
||||
break;
|
||||
case SDLK_BACKSPACE:
|
||||
set_key_up(e, KEY_TEXT_BACKSPACE);
|
||||
|
|
@ -1088,14 +957,12 @@ void InputManager::backend_key_up_update(const SDL_KeyboardEvent& e) {
|
|||
set_key_up(e, KEY_TEXT_END);
|
||||
break;
|
||||
case SDLK_LSHIFT:
|
||||
set_key_up(e, KEY_TEXT_SHIFT);
|
||||
set_key_up(e, KEY_GENERIC_LSHIFT);
|
||||
break;
|
||||
case SDLK_LALT:
|
||||
set_key_up(e, KEY_GENERIC_LALT);
|
||||
break;
|
||||
case SDLK_LCTRL:
|
||||
set_key_up(e, KEY_TEXT_CTRL);
|
||||
set_key_up(e, KEY_GENERIC_LCTRL);
|
||||
break;
|
||||
case SDLK_C:
|
||||
|
|
@ -1117,53 +984,21 @@ void InputManager::backend_key_up_update(const SDL_KeyboardEvent& e) {
|
|||
set_key_up(e, KEY_TEXT_REDO);
|
||||
break;
|
||||
case SDLK_RETURN:
|
||||
set_key_up(e, KEY_TEXT_ENTER);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_ENTER, .down = e.down, .repeat = e.repeat});
|
||||
set_key_up(e, KEY_GENERIC_ENTER);
|
||||
break;
|
||||
case SDLK_TAB:
|
||||
set_key_up(e, KEY_TEXT_TAB);
|
||||
break;
|
||||
case SDLK_ESCAPE:
|
||||
set_key_up(e, KEY_TEXT_ESCAPE);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_TEXT_ESCAPE, .down = e.down, .repeat = e.repeat});
|
||||
set_key_up(e, KEY_GENERIC_ESCAPE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for(auto& p : keyAssignments) {
|
||||
if(p.first.y() == kPress) { // Dont try matching modifiers when setting key to go up
|
||||
for(auto& p : keyAssignments)
|
||||
if(p.first.y() == kPress) // Dont try matching modifiers when setting key to go up
|
||||
set_key_up(e, p.second);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = p.second, .down = e.down, .repeat = e.repeat});
|
||||
}
|
||||
}
|
||||
|
||||
switch(kPress) {
|
||||
case SDLK_UP:
|
||||
set_key_up(e, KEY_GENERIC_UP);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_UP, .down = e.down, .repeat = e.repeat});
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
set_key_up(e, KEY_GENERIC_DOWN);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_DOWN, .down = e.down, .repeat = e.repeat});
|
||||
break;
|
||||
case SDLK_LEFT:
|
||||
set_key_up(e, KEY_GENERIC_LEFT);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_LEFT, .down = e.down, .repeat = e.repeat});
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
set_key_up(e, KEY_GENERIC_RIGHT);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_RIGHT, .down = e.down, .repeat = e.repeat});
|
||||
break;
|
||||
case SDLK_RETURN:
|
||||
set_key_up(e, KEY_GENERIC_ENTER);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_ENTER, .down = e.down, .repeat = e.repeat});
|
||||
break;
|
||||
case SDLK_ESCAPE:
|
||||
set_key_up(e, KEY_GENERIC_ESCAPE);
|
||||
main.input_key_callback(KeyCallbackArgs{.key = KEY_GENERIC_ESCAPE, .down = e.down, .repeat = e.repeat});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void InputManager::Mouse::set_pos(const Vector2f& newPos) {
|
||||
|
|
|
|||
|
|
@ -149,34 +149,26 @@ struct InputManager {
|
|||
int androidInputType;
|
||||
};
|
||||
|
||||
void set_rich_text_box_input_front(const std::shared_ptr<RichText::TextBox>& nTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& nCursor, bool isRichTextBox, const std::shared_ptr<SCollision::AABB<float>>& textboxRect, const TextInputProperties& inputProps, const std::shared_ptr<RichText::TextStyleModifier::ModifierMap>& nModMap = nullptr);
|
||||
void set_rich_text_box_input_back(const std::shared_ptr<RichText::TextBox>& nTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& nCursor, bool isRichTextBox, const std::shared_ptr<SCollision::AABB<float>>& textboxRect, const TextInputProperties& inputProps, const std::shared_ptr<RichText::TextStyleModifier::ModifierMap>& nModMap = nullptr);
|
||||
void remove_rich_text_box_input(const std::shared_ptr<RichText::TextBox>& nTextBox);
|
||||
unsigned set_text_box_front(const std::optional<SCollision::AABB<float>>& textboxRect, const TextInputProperties& inputProps);
|
||||
unsigned set_text_box_back(const std::optional<SCollision::AABB<float>>& textboxRect, const TextInputProperties& inputProps);
|
||||
void remove_text_box(unsigned textboxID);
|
||||
|
||||
struct Text {
|
||||
bool is_accepting_input();
|
||||
|
||||
void add_textbox_undo(const RichText::TextBox::Cursor& prevCursor, const RichText::TextData& prevRichText);
|
||||
void do_textbox_operation_with_undo(const std::function<void()>& func);
|
||||
|
||||
private:
|
||||
struct TextBoxInfo {
|
||||
bool isRichTextBox;
|
||||
std::shared_ptr<RichText::TextBox> textBox;
|
||||
std::shared_ptr<RichText::TextBox::Cursor> cursor;
|
||||
std::shared_ptr<SCollision::AABB<float>> rect;
|
||||
std::shared_ptr<RichText::TextStyleModifier::ModifierMap> modMap;
|
||||
std::optional<SCollision::AABB<float>> rect;
|
||||
TextInputProperties textInputProperties;
|
||||
UndoManager textboxUndo;
|
||||
unsigned id;
|
||||
};
|
||||
|
||||
void update_accepting_input(SDL_Window* window);
|
||||
|
||||
bool isNextPasteRich = false;
|
||||
|
||||
std::optional<SDL_PropertiesID> propID;
|
||||
|
||||
std::deque<TextBoxInfo> textBoxes;
|
||||
unsigned get_id();
|
||||
|
||||
friend struct InputManager;
|
||||
} text;
|
||||
|
|
@ -224,26 +216,17 @@ struct InputManager {
|
|||
KEY_ASSIGNABLE_COUNT, // Not a real key
|
||||
|
||||
// Unassignable
|
||||
KEY_TEXT_DOWN,
|
||||
KEY_TEXT_UP,
|
||||
KEY_TEXT_LEFT,
|
||||
KEY_TEXT_RIGHT,
|
||||
KEY_TEXT_BACKSPACE,
|
||||
KEY_TEXT_DELETE,
|
||||
KEY_TEXT_HOME,
|
||||
KEY_TEXT_END,
|
||||
KEY_TEXT_SHIFT,
|
||||
KEY_TEXT_COPY,
|
||||
KEY_TEXT_CUT,
|
||||
KEY_TEXT_PASTE,
|
||||
KEY_TEXT_ENTER,
|
||||
KEY_TEXT_TAB,
|
||||
KEY_TEXT_CTRL,
|
||||
KEY_TEXT_META,
|
||||
KEY_TEXT_SELECTALL,
|
||||
KEY_TEXT_UNDO,
|
||||
KEY_TEXT_REDO,
|
||||
KEY_TEXT_ESCAPE,
|
||||
KEY_GENERIC_UP,
|
||||
KEY_GENERIC_DOWN,
|
||||
KEY_GENERIC_LEFT,
|
||||
|
|
@ -254,6 +237,7 @@ struct InputManager {
|
|||
KEY_GENERIC_LALT,
|
||||
KEY_GENERIC_LCTRL,
|
||||
KEY_GENERIC_LMETA,
|
||||
|
||||
KEY_COUNT
|
||||
};
|
||||
|
||||
|
|
@ -269,8 +253,7 @@ struct InputManager {
|
|||
void touch_finger_do_mouse_up(const SDL_TouchFingerEvent& f);
|
||||
void touch_finger_do_mouse_motion(const SDL_TouchFingerEvent& f);
|
||||
|
||||
void add_text_to_textbox(const std::string& inputText);
|
||||
|
||||
void backend_input_text_event(const std::string& str);
|
||||
void backend_drop_file_event(const SDL_DropEvent& e);
|
||||
void backend_drop_text_event(const SDL_DropEvent& e);
|
||||
void backend_mouse_button_up_update(const SDL_MouseButtonEvent& e);
|
||||
|
|
@ -293,9 +276,14 @@ struct InputManager {
|
|||
void set_clipboard_plain_and_richtext_pair(const std::pair<std::string, RichText::TextData>& plainAndRichtextPair);
|
||||
std::string get_clipboard_str_SDL();
|
||||
void get_clipboard_image_data_SDL(const std::function<void(std::string_view data)>& callback);
|
||||
void call_text_paste(bool isRichTextPaste);
|
||||
void process_text_paste(const std::string& plainClipboardStr);
|
||||
|
||||
struct TextPasteCallbackArgs {
|
||||
std::string text;
|
||||
std::optional<RichText::TextData> richText;
|
||||
};
|
||||
void call_text_paste(const std::function<void(const TextPasteCallbackArgs&)>& pasteCallbackFunc);
|
||||
void process_text_paste(const std::string& pasteStr);
|
||||
std::function<void(const TextPasteCallbackArgs&)> pasteCallback;
|
||||
std::optional<RichText::TextData> lastCopiedRichText;
|
||||
|
||||
std::string key_assignment_to_str(const Vector2ui32& k) const;
|
||||
|
|
|
|||
|
|
@ -372,12 +372,12 @@ void MainProgram::input_key_callback(const InputManager::KeyCallbackArgs& key) {
|
|||
world->input_key_callback(key);
|
||||
}
|
||||
|
||||
void MainProgram::input_text_key_callback() {
|
||||
g.input_text_key_callback();
|
||||
void MainProgram::input_text_key_callback(const InputManager::KeyCallbackArgs& key) {
|
||||
g.input_text_key_callback(key);
|
||||
}
|
||||
|
||||
void MainProgram::input_text_input_callback() {
|
||||
g.input_text_input_callback();
|
||||
void MainProgram::input_text_callback(const std::string& str) {
|
||||
g.input_text_callback(str);
|
||||
}
|
||||
|
||||
void MainProgram::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {
|
||||
|
|
|
|||
|
|
@ -126,8 +126,8 @@ class MainProgram {
|
|||
void input_drop_file_callback(const InputManager::DropCallbackArgs& drop);
|
||||
void input_drop_text_callback(const InputManager::DropCallbackArgs& drop);
|
||||
void input_key_callback(const InputManager::KeyCallbackArgs& key);
|
||||
void input_text_key_callback();
|
||||
void input_text_input_callback();
|
||||
void input_text_key_callback(const InputManager::KeyCallbackArgs& key);
|
||||
void input_text_callback(const std::string& str);
|
||||
void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button);
|
||||
void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion);
|
||||
void input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel);
|
||||
|
|
|
|||
|
|
@ -145,14 +145,12 @@ void TextBox::process_key_input(Cursor& cur, InputKey in, bool ctrl, bool shift,
|
|||
cur.selectionEndPos = cur.selectionBeginPos = cur.pos = remove(cur.selectionBeginPos, cur.selectionEndPos);
|
||||
else
|
||||
cur.selectionEndPos = cur.selectionBeginPos = cur.pos = remove(cur.pos, move(ctrl ? Movement::LEFT_WORD : Movement::LEFT, cur.pos));
|
||||
if(onUserTextEdit) onUserTextEdit();
|
||||
break;
|
||||
case InputKey::DEL:
|
||||
if(cur.selectionBeginPos != cur.selectionEndPos)
|
||||
cur.selectionEndPos = cur.selectionBeginPos = cur.pos = remove(cur.selectionBeginPos, cur.selectionEndPos);
|
||||
else
|
||||
cur.selectionEndPos = cur.selectionBeginPos = cur.pos = remove(cur.pos, move(ctrl ? Movement::RIGHT_WORD : Movement::RIGHT, cur.pos));
|
||||
if(onUserTextEdit) onUserTextEdit();
|
||||
break;
|
||||
case InputKey::ENTER:
|
||||
process_text_input(cur, "\n", inputModMap);
|
||||
|
|
@ -244,7 +242,6 @@ std::pair<std::string, TextData> TextBox::process_cut(Cursor& cur) {
|
|||
cur.selectionEndPos = cur.selectionBeginPos = cur.pos = remove(cur.selectionBeginPos, cur.selectionEndPos);
|
||||
cur.previousX = std::nullopt;
|
||||
if(onChange) onChange();
|
||||
if(onUserTextEdit) onUserTextEdit();
|
||||
inputChangedTextBox = true;
|
||||
}
|
||||
return toRet;
|
||||
|
|
@ -257,7 +254,6 @@ void TextBox::process_text_input(Cursor& cur, const std::string& in, const std::
|
|||
cur.selectionEndPos = cur.selectionBeginPos = cur.pos = insert(cur.pos, in, inputModMap);
|
||||
cur.previousX = std::nullopt;
|
||||
if(onChange) onChange();
|
||||
if(onUserTextEdit) onUserTextEdit();
|
||||
inputChangedTextBox = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -269,7 +265,6 @@ void TextBox::process_rich_text_input(Cursor& cur, const TextData& richText) {
|
|||
cur.selectionEndPos = cur.selectionBeginPos = cur.pos = insert_rich_text(cur.pos, richText);
|
||||
cur.previousX = std::nullopt;
|
||||
if(onChange) onChange();
|
||||
if(onUserTextEdit) onUserTextEdit();
|
||||
inputChangedTextBox = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -502,7 +497,6 @@ void TextBox::set_rich_text_data(const TextData& richText) {
|
|||
|
||||
void TextBox::set_rich_text_data_for_undo_redo(const TextData& richText) {
|
||||
set_rich_text_data(richText);
|
||||
if(onUserTextEdit) onUserTextEdit();
|
||||
}
|
||||
|
||||
std::string TextBox::get_string() {
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ class TextBox {
|
|||
|
||||
bool inputChangedTextBox = false;
|
||||
std::function<void()> onChange;
|
||||
std::function<void()> onUserTextEdit;
|
||||
|
||||
enum class Movement {
|
||||
NOWHERE,
|
||||
|
|
|
|||
123
src/RichTextUserInput.cpp
Normal file
123
src/RichTextUserInput.cpp
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
#include "RichTextUserInput.hpp"
|
||||
|
||||
template <typename T> std::optional<T> shared_ptr_to_opt(const std::shared_ptr<T> o) {
|
||||
if(o)
|
||||
return *o;
|
||||
else
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
RichTextUserInput::RichTextUserInput(const std::shared_ptr<RichText::TextBox>& initTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& initCursor, const std::shared_ptr<RichText::TextStyleModifier::ModifierMap>& initModMap, const std::function<void()>& initOnTextEdit):
|
||||
textBox(initTextBox),
|
||||
cursor(initCursor),
|
||||
modMap(initModMap),
|
||||
onTextEdit(initOnTextEdit)
|
||||
{}
|
||||
|
||||
void RichTextUserInput::add_text_to_textbox(const std::string& inputText) {
|
||||
do_textbox_operation_with_undo([&]() {
|
||||
textBox->process_text_input(*cursor, inputText, shared_ptr_to_opt(modMap));
|
||||
});
|
||||
onTextEdit();
|
||||
}
|
||||
|
||||
void RichTextUserInput::add_textbox_undo(const RichText::TextBox::Cursor& prevCursor, const RichText::TextData& prevRichText) {
|
||||
textboxUndo.push({[&, prevCursor = prevCursor, prevRichText = prevRichText]() {
|
||||
textBox->set_rich_text_data_for_undo_redo(prevRichText);
|
||||
cursor->selectionBeginPos = cursor->selectionEndPos = cursor->pos = std::max(prevCursor.selectionEndPos, prevCursor.selectionBeginPos);
|
||||
cursor->previousX = std::nullopt;
|
||||
onTextEdit();
|
||||
return true;
|
||||
},
|
||||
[&, currentCursor = *cursor, currentRichText = textBox->get_rich_text_data()]() {
|
||||
textBox->set_rich_text_data_for_undo_redo(currentRichText);
|
||||
cursor->selectionBeginPos = cursor->selectionEndPos = cursor->pos = std::max(currentCursor.selectionEndPos, currentCursor.selectionBeginPos);
|
||||
cursor->previousX = std::nullopt;
|
||||
onTextEdit();
|
||||
return true;
|
||||
}});
|
||||
}
|
||||
|
||||
void RichTextUserInput::do_textbox_operation_with_undo(const std::function<void()>& func) {
|
||||
auto prevRichText = textBox->get_rich_text_data();
|
||||
auto prevCursor = *cursor;
|
||||
func();
|
||||
add_textbox_undo(prevCursor, prevRichText);
|
||||
onTextEdit();
|
||||
}
|
||||
|
||||
void RichTextUserInput::input_key_callback(InputManager& input, const InputManager::KeyCallbackArgs& key) {
|
||||
std::optional<RichText::TextStyleModifier::ModifierMap> modMapOpt = shared_ptr_to_opt(modMap);
|
||||
|
||||
if(key.down) {
|
||||
switch(key.key) {
|
||||
case InputManager::KEY_GENERIC_UP:
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::UP, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
|
||||
break;
|
||||
case InputManager::KEY_GENERIC_DOWN:
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::DOWN, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
|
||||
break;
|
||||
case InputManager::KEY_GENERIC_LEFT:
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::LEFT, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
|
||||
break;
|
||||
case InputManager::KEY_GENERIC_RIGHT:
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::RIGHT, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
|
||||
break;
|
||||
case InputManager::KEY_TEXT_BACKSPACE:
|
||||
do_textbox_operation_with_undo([&] {
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::BACKSPACE, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
|
||||
});
|
||||
break;
|
||||
case InputManager::KEY_TEXT_DELETE:
|
||||
do_textbox_operation_with_undo([&] {
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::DEL, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
|
||||
});
|
||||
break;
|
||||
case InputManager::KEY_TEXT_HOME:
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::HOME, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
|
||||
break;
|
||||
case InputManager::KEY_TEXT_END:
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::END, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
|
||||
break;
|
||||
case InputManager::KEY_TEXT_COPY:
|
||||
input.set_clipboard_plain_and_richtext_pair(textBox->process_copy(*cursor));
|
||||
break;
|
||||
case InputManager::KEY_TEXT_CUT:
|
||||
do_textbox_operation_with_undo([&] {
|
||||
input.set_clipboard_plain_and_richtext_pair(textBox->process_cut(*cursor));
|
||||
});
|
||||
break;
|
||||
case InputManager::KEY_TEXT_PASTE:
|
||||
do_textbox_operation_with_undo([&]() {
|
||||
input.call_text_paste([textBox = textBox, cursor = cursor, modMapOpt] (const InputManager::TextPasteCallbackArgs& pasteArgs) {
|
||||
if(pasteArgs.richText.has_value())
|
||||
textBox->process_rich_text_input(*cursor, pasteArgs.richText.value());
|
||||
else
|
||||
textBox->process_text_input(*cursor, pasteArgs.text, modMapOpt);
|
||||
});
|
||||
});
|
||||
break;
|
||||
case InputManager::KEY_TEXT_SELECTALL:
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::SELECT_ALL, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
|
||||
break;
|
||||
case InputManager::KEY_TEXT_UNDO:
|
||||
textboxUndo.undo();
|
||||
break;
|
||||
case InputManager::KEY_TEXT_REDO:
|
||||
textboxUndo.redo();
|
||||
break;
|
||||
case InputManager::KEY_GENERIC_ENTER:
|
||||
do_textbox_operation_with_undo([&] {
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::ENTER, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
|
||||
});
|
||||
break;
|
||||
case InputManager::KEY_TEXT_TAB:
|
||||
do_textbox_operation_with_undo([&] {
|
||||
textBox->process_key_input(*cursor, RichText::TextBox::InputKey::TAB, input.ctrl_or_meta_held(), input.key(InputManager::KEY_GENERIC_LSHIFT).held, modMapOpt);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/RichTextUserInput.hpp
Normal file
19
src/RichTextUserInput.hpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
#include "RichText/TextBox.hpp"
|
||||
#include "UndoManager.hpp"
|
||||
#include "InputManager.hpp"
|
||||
|
||||
class RichTextUserInput {
|
||||
public:
|
||||
RichTextUserInput(const std::shared_ptr<RichText::TextBox>& initTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& initCursor, const std::shared_ptr<RichText::TextStyleModifier::ModifierMap>& initModMap, const std::function<void()>& initOnTextEdit);
|
||||
void input_key_callback(InputManager& input, const InputManager::KeyCallbackArgs& key);
|
||||
void add_text_to_textbox(const std::string& inputText);
|
||||
private:
|
||||
void do_textbox_operation_with_undo(const std::function<void()>& func);
|
||||
void add_textbox_undo(const RichText::TextBox::Cursor& prevCursor, const RichText::TextData& prevRichText);
|
||||
std::shared_ptr<RichText::TextBox> textBox;
|
||||
std::shared_ptr<RichText::TextBox::Cursor> cursor;
|
||||
std::shared_ptr<RichText::TextStyleModifier::ModifierMap> modMap;
|
||||
UndoManager textboxUndo;
|
||||
std::function<void()> onTextEdit;
|
||||
};
|
||||
|
|
@ -752,7 +752,7 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) {
|
|||
mS.m->input.backend_key_up_update(event->key);
|
||||
break;
|
||||
case SDL_EVENT_TEXT_INPUT:
|
||||
mS.m->input.add_text_to_textbox(event->text.text);
|
||||
mS.m->input.backend_input_text_event(event->text.text);
|
||||
break;
|
||||
case SDL_EVENT_DROP_FILE:
|
||||
mS.m->update_scale_and_density();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue