Added text edit right click menu
This commit is contained in:
parent
f227e074f8
commit
d57d2f4752
10 changed files with 84 additions and 115 deletions
|
|
@ -32,9 +32,13 @@ EM_JS_INLINE(void, paste_js, (paste_handler callback, void *callback_data), {
|
|||
/// Register the given callback to handle paste events. Callback data pointer is passed through to the callback.
|
||||
/// Paste handler callback signature is:
|
||||
/// void my_handler(std::string const &paste_data, void *callback_data = nullptr);
|
||||
document.addEventListener('paste', (event) => {
|
||||
Module["ccall"]('emscripten_browser_clipboard_detail_paste_return', 'number', ['string', 'number', 'number'], [event.clipboardData.getData('text/plain'), callback, callback_data]);
|
||||
});
|
||||
navigator.clipboard.readText()
|
||||
.then(text => {
|
||||
Module["ccall"]('emscripten_browser_clipboard_detail_paste_return', 'number', ['string', 'number', 'number'], [text, callback, callback_data]);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Failed to read clipboard contents: ', err);
|
||||
});
|
||||
});
|
||||
|
||||
EM_JS_INLINE(void, copy_js, (copy_handler callback, void *callback_data), {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
#include "DrawingProgramEditToolBase.hpp"
|
||||
#include "../MainProgram.hpp"
|
||||
|
||||
DrawingProgramEditToolBase::DrawingProgramEditToolBase(DrawingProgram& initDrawP):
|
||||
drawP(initDrawP)
|
||||
{}
|
||||
|
||||
bool DrawingProgramEditToolBase::right_click_popup_gui(const std::shared_ptr<DrawComponent>& comp, Vector2f popupPos) {
|
||||
Toolbar& t = drawP.world.main.toolbar;
|
||||
t.paint_popup(popupPos);
|
||||
return true;
|
||||
}
|
||||
|
||||
DrawingProgramEditToolBase::~DrawingProgramEditToolBase() {}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ class DrawingProgramEditToolBase {
|
|||
virtual void commit_edit_updates(const std::shared_ptr<DrawComponent>& a, std::any& prevData) = 0;
|
||||
virtual bool edit_update(const std::shared_ptr<DrawComponent>& a) = 0;
|
||||
virtual bool edit_gui(const std::shared_ptr<DrawComponent>& a) = 0;
|
||||
virtual bool right_click_popup_gui(const std::shared_ptr<DrawComponent>& comp, Vector2f popupPos);
|
||||
virtual ~DrawingProgramEditToolBase();
|
||||
protected:
|
||||
DrawingProgram& drawP;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,10 @@ void EditTool::gui_toolbox() {
|
|||
}
|
||||
|
||||
bool EditTool::right_click_popup_gui(Vector2f popupPos) {
|
||||
return drawP.selection_action_menu(popupPos);
|
||||
if(controls.isEditing)
|
||||
return controls.compEditTool->right_click_popup_gui(controls.compToEdit.lock(), popupPos);
|
||||
else
|
||||
return drawP.selection_action_menu(popupPos);
|
||||
}
|
||||
|
||||
void EditTool::add_point_handle(const HandleData& handle) {
|
||||
|
|
|
|||
|
|
@ -152,6 +152,37 @@ bool TextBoxEditTool::edit_gui(const std::shared_ptr<DrawComponent>& comp) {
|
|||
return oldInputChangedTextBox;
|
||||
}
|
||||
|
||||
bool TextBoxEditTool::right_click_popup_gui(const std::shared_ptr<DrawComponent>& comp, Vector2f popupPos) {
|
||||
Toolbar& t = drawP.world.main.toolbar;
|
||||
bool shouldClose = false;
|
||||
std::shared_ptr<DrawTextBox> a = std::static_pointer_cast<DrawTextBox>(comp);
|
||||
t.gui.list_popup_menu("Text popup menu", popupPos, [&]() {
|
||||
t.gui.text_label_light("Text menu");
|
||||
InputManager& input = drawP.world.main.input;
|
||||
if(t.gui.text_button_left_transparent("Paste", "Paste")) {
|
||||
input.call_text_paste(true);
|
||||
shouldClose = true;
|
||||
}
|
||||
if(t.gui.text_button_left_transparent("Paste without formatting", "Paste without formatting")) {
|
||||
input.call_text_paste(false);
|
||||
shouldClose = true;
|
||||
}
|
||||
if(a->cursor->selectionBeginPos != a->cursor->selectionEndPos) {
|
||||
if(t.gui.text_button_left_transparent("Copy", "Copy")) {
|
||||
input.set_clipboard_plain_and_richtext_pair(a->textBox->process_copy(*a->cursor));
|
||||
shouldClose = true;
|
||||
}
|
||||
if(t.gui.text_button_left_transparent("Cut", "Cut")) {
|
||||
input.text.do_textbox_operation_with_undo([&]() {
|
||||
input.set_clipboard_plain_and_richtext_pair(a->textBox->process_cut(*a->cursor));
|
||||
});
|
||||
shouldClose = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
return !shouldClose;
|
||||
}
|
||||
|
||||
void TextBoxEditTool::hold_undo_data(const std::string& undoName, const std::shared_ptr<DrawTextBox>& a) {
|
||||
auto it = undoHeldData.find(undoName);
|
||||
if(it != undoHeldData.end()) {
|
||||
|
|
@ -286,7 +317,7 @@ bool TextBoxEditTool::edit_update(const std::shared_ptr<DrawComponent>& comp) {
|
|||
|
||||
bool collidesWithBox = a->collides_with_cam_coords(drawP.world.drawData.cam.c, mousePointCollection);
|
||||
|
||||
input.text.set_rich_text_box_input(a->textBox, a->cursor, currentMods);
|
||||
input.text.set_rich_text_box_input(a->textBox, a->cursor, true, currentMods);
|
||||
a->textBox->process_mouse_left_button(*a->cursor, a->get_mouse_pos(drawP), (drawP.controls.leftClick && collidesWithBox) ? drawP.world.main.input.mouse.leftClicks : 0, drawP.controls.leftClickHeld, input.key(InputManager::KEY_GENERIC_LSHIFT).held);
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ class TextBoxEditTool : public DrawingProgramEditToolBase {
|
|||
virtual void commit_edit_updates(const std::shared_ptr<DrawComponent>& a, std::any& prevData) override;
|
||||
virtual bool edit_update(const std::shared_ptr<DrawComponent>& a) override;
|
||||
virtual bool edit_gui(const std::shared_ptr<DrawComponent>& a) override;
|
||||
virtual bool right_click_popup_gui(const std::shared_ptr<DrawComponent>& comp, Vector2f popupPos) override;
|
||||
private:
|
||||
struct TextBoxEditToolAllData {
|
||||
DrawTextBox::Data textboxData;
|
||||
|
|
|
|||
|
|
@ -89,14 +89,7 @@ struct UpdateInputData {
|
|||
bool down = false;
|
||||
bool leftShift = false;
|
||||
bool leftCtrl = false;
|
||||
bool home = false;
|
||||
bool del = false;
|
||||
bool backspace = false;
|
||||
bool enter = false;
|
||||
bool selectAll = false;
|
||||
bool copy = false;
|
||||
bool paste = false;
|
||||
bool cut = false;
|
||||
bool escape = false;
|
||||
} key;
|
||||
|
||||
|
|
|
|||
|
|
@ -48,26 +48,6 @@ InputManager::InputManager() {
|
|||
defaultKeyAssignments[{0, SDLK_SPACE}] = KEY_HOLD_TO_PAN;
|
||||
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// Without this, SDL eats the CTRL-V event that initiates the paste event
|
||||
// https://github.com/pthom/hello_imgui/issues/3#issuecomment-1564536870
|
||||
EM_ASM({
|
||||
window.addEventListener('keydown', function(event) {
|
||||
if((event.ctrlKey || event.metaKey) && (event.key == 'v' || event.code == 'KeyV')) {
|
||||
if(Module["ccall"]('is_text_input_happening', 'number', [], []) === 1)
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
|
||||
emscripten_browser_clipboard::paste([](std::string&& pasteData, void* callbackData){
|
||||
InputManager* inMan = (InputManager*)callbackData;
|
||||
inMan->clipboardPasteEventHappened = true;
|
||||
inMan->clipboardPasteEventData["text/plain"] = pasteData;
|
||||
inMan->process_text_paste();
|
||||
}, this);
|
||||
#endif
|
||||
|
||||
keyAssignments = defaultKeyAssignments;
|
||||
}
|
||||
|
||||
|
|
@ -81,11 +61,12 @@ void InputManager::text_input_silence_everything() {
|
|||
text.newInput.clear();
|
||||
}
|
||||
|
||||
void InputManager::Text::set_rich_text_box_input(const std::shared_ptr<RichText::TextBox>& nTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& nCursor, const std::optional<RichText::TextStyleModifier::ModifierMap>& nModMap) {
|
||||
void InputManager::Text::set_rich_text_box_input(const std::shared_ptr<RichText::TextBox>& nTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& nCursor, bool isRichTextBox, const std::optional<RichText::TextStyleModifier::ModifierMap>& nModMap) {
|
||||
set_accepting_input();
|
||||
newTextBox = nTextBox;
|
||||
newCursor = nCursor;
|
||||
newModMap = nModMap;
|
||||
newIsRichTextBox = isRichTextBox;
|
||||
}
|
||||
|
||||
void InputManager::Text::add_text_to_textbox(const std::string& inputText) {
|
||||
|
|
@ -129,41 +110,11 @@ void InputManager::Text::do_textbox_operation_with_undo(const std::function<void
|
|||
}
|
||||
}
|
||||
|
||||
bool InputManager::get_clipboard_paste_happened() {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
return clipboardPasteEventHappened;
|
||||
#else
|
||||
return key(KEY_TEXT_PASTE).repeat;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string InputManager::get_clipboard_str() {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
auto it = clipboardPasteEventData.find("text/plain");
|
||||
if(it == clipboardPasteEventData.end())
|
||||
return "";
|
||||
return it->second;
|
||||
#else
|
||||
std::string InputManager::get_clipboard_str_SDL() {
|
||||
char* data = SDL_GetClipboardText();
|
||||
std::string toRet(data);
|
||||
SDL_free(data);
|
||||
return toRet;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string InputManager::get_clipboard_data_for_mimetype(const std::string& mimeType) {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
auto it = clipboardPasteEventData.find(mimeType);
|
||||
if(it == clipboardPasteEventData.end())
|
||||
return "";
|
||||
return it->second;
|
||||
#else
|
||||
size_t datSize = 0;
|
||||
void* dat = SDL_GetClipboardData(mimeType.c_str(), &datSize);
|
||||
if(!dat)
|
||||
return "";
|
||||
return std::string(static_cast<char*>(dat), datSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputManager::set_clipboard_str(std::string_view s) {
|
||||
|
|
@ -180,30 +131,6 @@ void InputManager::set_clipboard_plain_and_richtext_pair(const std::pair<std::st
|
|||
lastCopiedRichText = plainAndRichtextPair.second;
|
||||
}
|
||||
|
||||
void InputManager::set_clipboard_data(const std::unordered_map<std::string, std::string>& newClipboardData) {
|
||||
SDL_ClearClipboardData();
|
||||
clipboardData = newClipboardData;
|
||||
|
||||
std::vector<const char*> mimeTypes;
|
||||
for(auto& [k, v] : clipboardData)
|
||||
mimeTypes.emplace_back(k.c_str());
|
||||
|
||||
SDL_SetClipboardData(
|
||||
[](void *userdata, const char *mime_type, size_t *size) {
|
||||
std::unordered_map<std::string, std::string>& clipboardData = *static_cast<std::unordered_map<std::string, std::string>*>(userdata);
|
||||
std::string mimeTypeStr(mime_type);
|
||||
auto it = clipboardData.find(mimeTypeStr);
|
||||
std::cout << "requesting: " << mime_type << std::endl;
|
||||
if(it == clipboardData.end())
|
||||
return static_cast<const void*>(nullptr);
|
||||
*size = it->second.length();
|
||||
return static_cast<const void*>(it->second.c_str());
|
||||
},
|
||||
[](void *userdata) {
|
||||
},
|
||||
static_cast<void*>(&clipboardData), mimeTypes.data(), mimeTypes.size());
|
||||
}
|
||||
|
||||
std::string InputManager::key_assignment_to_str(const Vector2ui32& k) {
|
||||
std::string toRet;
|
||||
if(k.x() & SDL_KMOD_CTRL)
|
||||
|
|
@ -375,7 +302,7 @@ void InputManager::backend_key_down_update(const SDL_KeyboardEvent& e) {
|
|||
set_key_down(e, KEY_TEXT_PASTE);
|
||||
if(text.textBox && key(KEY_TEXT_PASTE).repeat)
|
||||
text.do_textbox_operation_with_undo([&]() {
|
||||
process_text_paste();
|
||||
call_text_paste(true);
|
||||
});
|
||||
break;
|
||||
case SDLK_A:
|
||||
|
|
@ -427,11 +354,23 @@ void InputManager::backend_key_down_update(const SDL_KeyboardEvent& e) {
|
|||
set_key_down(e, f->second);
|
||||
}
|
||||
|
||||
void InputManager::process_text_paste() {
|
||||
void InputManager::call_text_paste(bool isRichTextPaste) {
|
||||
text.isNextPasteRich = isRichTextPaste;
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_browser_clipboard::paste([](std::string&& pasteData, void* callbackData){
|
||||
InputManager* inMan = (InputManager*)callbackData;
|
||||
std::string pData = pasteData;
|
||||
inMan->process_text_paste(pData);
|
||||
}, this);
|
||||
#else
|
||||
process_text_paste(get_clipboard_str_SDL());
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputManager::process_text_paste(const std::string& plainClipboardStr) {
|
||||
if(text.textBox) {
|
||||
// Workaround for not being able to copy richtext to system clipboard, this should at least work within the application itself
|
||||
std::string plainClipboardStr = get_clipboard_str();
|
||||
if(lastCopiedRichText.has_value()) {
|
||||
if(text.isRichTextBox && text.isNextPasteRich && lastCopiedRichText.has_value()) {
|
||||
if(lastCopiedRichText.value().get_plain_text() == plainClipboardStr)
|
||||
text.textBox->process_rich_text_input(*text.cursor, lastCopiedRichText.value());
|
||||
else
|
||||
|
|
@ -546,8 +485,12 @@ void InputManager::frame_reset(const Vector2i& windowSize) {
|
|||
text.cursor = text.newCursor;
|
||||
text.textBox = text.newTextBox;
|
||||
text.modMap = text.newModMap;
|
||||
text.isRichTextBox = text.newIsRichTextBox;
|
||||
|
||||
text.newCursor = nullptr;
|
||||
text.newTextBox = nullptr;
|
||||
text.newModMap = std::nullopt;
|
||||
text.newIsRichTextBox = false;
|
||||
|
||||
text.newInput.clear();
|
||||
droppedItems.clear();
|
||||
|
|
|
|||
|
|
@ -89,17 +89,21 @@ struct InputManager {
|
|||
void set_accepting_input();
|
||||
bool get_accepting_input();
|
||||
|
||||
void set_rich_text_box_input(const std::shared_ptr<RichText::TextBox>& nTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& nCursor, const std::optional<RichText::TextStyleModifier::ModifierMap>& nModMap = std::nullopt);
|
||||
void set_rich_text_box_input(const std::shared_ptr<RichText::TextBox>& nTextBox, const std::shared_ptr<RichText::TextBox::Cursor>& nCursor, bool isRichTextBox, const std::optional<RichText::TextStyleModifier::ModifierMap>& nModMap = std::nullopt);
|
||||
void add_text_to_textbox(const std::string& inputText);
|
||||
|
||||
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:
|
||||
bool isNextPasteRich = false;
|
||||
|
||||
bool isRichTextBox;
|
||||
std::shared_ptr<RichText::TextBox> textBox;
|
||||
std::shared_ptr<RichText::TextBox::Cursor> cursor;
|
||||
std::optional<RichText::TextStyleModifier::ModifierMap> modMap;
|
||||
|
||||
bool newIsRichTextBox;
|
||||
std::shared_ptr<RichText::TextBox> newTextBox;
|
||||
std::shared_ptr<RichText::TextBox::Cursor> newCursor;
|
||||
std::optional<RichText::TextStyleModifier::ModifierMap> newModMap;
|
||||
|
|
@ -201,22 +205,11 @@ struct InputManager {
|
|||
void backend_key_up_update(const SDL_KeyboardEvent& e);
|
||||
void backend_key_down_update(const SDL_KeyboardEvent& e);
|
||||
|
||||
bool get_clipboard_paste_happened();
|
||||
std::string get_clipboard_str();
|
||||
|
||||
std::string get_clipboard_data_for_mimetype(const std::string& mimeType);
|
||||
|
||||
void set_clipboard_str(std::string_view s);
|
||||
void set_clipboard_plain_and_richtext_pair(const std::pair<std::string, RichText::TextData>& plainAndRichtextPair);
|
||||
void set_clipboard_data(const std::unordered_map<std::string, std::string>& newClipboardData);
|
||||
void process_text_paste();
|
||||
|
||||
std::unordered_map<std::string, std::string> clipboardData;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
bool clipboardPasteEventHappened = false;
|
||||
std::unordered_map<std::string, std::string> clipboardPasteEventData;
|
||||
#endif
|
||||
std::string get_clipboard_str_SDL();
|
||||
void call_text_paste(bool isRichTextPaste);
|
||||
void process_text_paste(const std::string& plainClipboardStr);
|
||||
|
||||
std::optional<RichText::TextData> lastCopiedRichText;
|
||||
|
||||
|
|
|
|||
|
|
@ -1983,17 +1983,10 @@ void Toolbar::initialize_io_before_update() {
|
|||
io->key.down = main.input.key(InputManager::KEY_TEXT_DOWN).repeat;
|
||||
io->key.leftShift = main.input.key(InputManager::KEY_TEXT_SHIFT).held;
|
||||
io->key.leftCtrl = main.input.key(InputManager::KEY_TEXT_CTRL).held;
|
||||
io->key.home = main.input.key(InputManager::KEY_TEXT_HOME).repeat;
|
||||
io->key.del = main.input.key(InputManager::KEY_TEXT_DELETE).repeat;
|
||||
io->key.backspace = main.input.key(InputManager::KEY_TEXT_BACKSPACE).repeat;
|
||||
io->key.enter = main.input.key(InputManager::KEY_TEXT_ENTER).repeat;
|
||||
io->key.selectAll = main.input.key(InputManager::KEY_TEXT_SELECTALL).repeat;
|
||||
io->key.copy = main.input.key(InputManager::KEY_TEXT_COPY).repeat;
|
||||
io->key.paste = main.input.get_clipboard_paste_happened();
|
||||
io->key.cut = main.input.key(InputManager::KEY_TEXT_CUT).repeat;
|
||||
io->key.escape = main.input.key(InputManager::KEY_GENERIC_ESCAPE).repeat;
|
||||
io->richTextBoxEdit = [&](std::shared_ptr<RichText::TextBox> t, std::shared_ptr<RichText::TextBox::Cursor> c) {
|
||||
main.input.text.set_rich_text_box_input(t, c);
|
||||
main.input.text.set_rich_text_box_input(t, c, false);
|
||||
};
|
||||
|
||||
if(io->acceptingTextInput)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue