From fab9e90ad83a0855d098054466230d68b014adcf Mon Sep 17 00:00:00 2001 From: Christian_Haitian Date: Sun, 18 Jul 2021 18:14:27 +0000 Subject: [PATCH] Merge additional updates from upstream --- README.md | 5 +- src/def.h | 8 +- src/fileUtils.cpp | 2 +- src/keyboard.cpp | 57 ++++++----- src/keyboard.h | 8 +- src/textEditor.cpp | 250 +++++++++++++++++++++++++++++++++++++++++---- src/textEditor.h | 12 +++ src/textInput.cpp | 2 +- 8 files changed, 294 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 3066bf2..ef1e81d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # 351Files -A Single panel file Manager tailored for Anbernic 351 devices: RG351V and RG351P. Can be easily adapted to any Linux-based device. +A single panel file Manager tailored for Anbernic 351 devices: RG351V and RG351P. Can be easily adapted to any Linux-based device. Based on DinguxCommander. * Original page: http://beyondds.free.fr/index.php?Dingoo-dinguxcommander @@ -45,6 +45,8 @@ Until then, you can install it manually with the following procedure: * Restart EmulationStation. '351Files' should now be an entry in the 'ports' menu. # Installation on ArkOS: +351Files should be integrated in ArkOS, in a future version. +Until then, you can install it manually with the following procedure: * Download the latest release for your device (351Files-vx.x_<device>_ArkOS.tgz) * Uncompress the .tgz file on your SD card in: /roms/ports * Edit file /roms/ports/gamelist.xml, and add: @@ -78,6 +80,7 @@ Text editor: * A: open virtual keyboard / validate * B: cancel / back * X: open context menu +* Y + d-pad: select text * R1/R2: page down * L1/L2 : page up diff --git a/src/def.h b/src/def.h index 12dc1ea..88c7401 100644 --- a/src/def.h +++ b/src/def.h @@ -120,7 +120,7 @@ // Size of dialog border #define DIALOG_BORDER 4 -// Scroll speed in file and image viewer +// Scroll speed in image viewer #define VIEWER_SCROLL_SPEED 20 // Button events @@ -141,6 +141,7 @@ #define BUTTON_HELD_RIGHT SDL_JoystickGetHat(g_joystick, 0) == SDL_HAT_RIGHT #define BUTTON_HELD_PAGEUP SDL_JoystickGetButton(g_joystick, 4) || SDL_JoystickGetButton(g_joystick, 10) #define BUTTON_HELD_PAGEDOWN SDL_JoystickGetButton(g_joystick, 5) || SDL_JoystickGetButton(g_joystick, 11) + #define BUTTON_HELD_SELECT SDL_JoystickGetButton(g_joystick, 3) #elif defined(DEVICE_RG351V) #define BUTTON_PRESSED_UP event.type == SDL_JOYHATMOTION && event.jhat.value == SDL_HAT_UP #define BUTTON_PRESSED_DOWN event.type == SDL_JOYHATMOTION && event.jhat.value == SDL_HAT_DOWN @@ -158,6 +159,7 @@ #define BUTTON_HELD_RIGHT SDL_JoystickGetHat(g_joystick, 0) == SDL_HAT_RIGHT #define BUTTON_HELD_PAGEUP SDL_JoystickGetButton(g_joystick, 4) || SDL_JoystickGetButton(g_joystick, 10) #define BUTTON_HELD_PAGEDOWN SDL_JoystickGetButton(g_joystick, 5) || SDL_JoystickGetButton(g_joystick, 11) + #define BUTTON_HELD_SELECT SDL_JoystickGetButton(g_joystick, 3) #elif defined(DEVICE_RGB10) #define BUTTON_PRESSED_UP event.type == SDL_JOYBUTTONDOWN && event.jbutton.button == 8 #define BUTTON_PRESSED_DOWN event.type == SDL_JOYBUTTONDOWN && event.jbutton.button == 9 @@ -175,6 +177,7 @@ #define BUTTON_HELD_RIGHT SDL_JoystickGetButton(g_joystick, 11) #define BUTTON_HELD_PAGEUP SDL_JoystickGetButton(g_joystick, 4) || SDL_JoystickGetButton(g_joystick, 14) #define BUTTON_HELD_PAGEDOWN SDL_JoystickGetButton(g_joystick, 5) || SDL_JoystickGetButton(g_joystick, 15) + #define BUTTON_HELD_SELECT SDL_JoystickGetButton(g_joystick, 2) #elif defined(DEVICE_RK2020) #define BUTTON_PRESSED_UP event.type == SDL_JOYBUTTONDOWN && event.jbutton.button == 6 #define BUTTON_PRESSED_DOWN event.type == SDL_JOYBUTTONDOWN && event.jbutton.button == 7 @@ -192,6 +195,7 @@ #define BUTTON_HELD_RIGHT SDL_JoystickGetButton(g_joystick, 9) #define BUTTON_HELD_PAGEUP SDL_JoystickGetButton(g_joystick, 4) || SDL_JoystickGetButton(g_joystick, 12) #define BUTTON_HELD_PAGEDOWN SDL_JoystickGetButton(g_joystick, 5) || SDL_JoystickGetButton(g_joystick, 13) + #define BUTTON_HELD_SELECT SDL_JoystickGetButton(g_joystick, 2) #elif defined(DEVICE_CHI) #define BUTTON_PRESSED_UP event.type == SDL_JOYBUTTONDOWN && event.jbutton.button == 10 #define BUTTON_PRESSED_DOWN event.type == SDL_JOYBUTTONDOWN && event.jbutton.button == 11 @@ -209,6 +213,7 @@ #define BUTTON_HELD_RIGHT SDL_JoystickGetButton(g_joystick, 13) #define BUTTON_HELD_PAGEUP SDL_JoystickGetButton(g_joystick, 4) || SDL_JoystickGetButton(g_joystick, 6) #define BUTTON_HELD_PAGEDOWN SDL_JoystickGetButton(g_joystick, 5) || SDL_JoystickGetButton(g_joystick, 7) + #define BUTTON_HELD_SELECT SDL_JoystickGetButton(g_joystick, 2) #else #define BUTTON_PRESSED_UP event.type == SDL_KEYDOWN && event.key.repeat == 0 && event.key.keysym.sym == SDLK_UP #define BUTTON_PRESSED_DOWN event.type == SDL_KEYDOWN && event.key.repeat == 0 && event.key.keysym.sym == SDLK_DOWN @@ -226,6 +231,7 @@ #define BUTTON_HELD_RIGHT SDL_GetKeyboardState(NULL)[SDL_SCANCODE_RIGHT] #define BUTTON_HELD_PAGEUP SDL_GetKeyboardState(NULL)[SDL_SCANCODE_PAGEUP] #define BUTTON_HELD_PAGEDOWN SDL_GetKeyboardState(NULL)[SDL_SCANCODE_PAGEDOWN] + #define BUTTON_HELD_SELECT SDL_GetKeyboardState(NULL)[SDL_SCANCODE_INSERT] #endif // Globals diff --git a/src/fileUtils.cpp b/src/fileUtils.cpp index 68e3415..a7bfc45 100644 --- a/src/fileUtils.cpp +++ b/src/fileUtils.cpp @@ -375,5 +375,5 @@ bool FileUtils::fileIsText(const std::string &p_path) while (fgets(buffer, sizeof(buffer), pipe) != NULL); pclose(pipe); line = buffer; - return line.substr(0, 4) == "text"; + return (line.substr(0, 4) == "text" && line.find("charset=us-ascii") != std::string::npos); } diff --git a/src/keyboard.cpp b/src/keyboard.cpp index fd111e8..f6bc9a5 100644 --- a/src/keyboard.cpp +++ b/src/keyboard.cpp @@ -18,8 +18,9 @@ Keyboard::Keyboard(IWindow *p_parent, const bool p_quitOnEnter): { m_cursorLoop = true; m_keyLabel[0] = "qwertyuiop asdfghjkl zxcvbnm_."; - m_keyLabel[1] = "QWERTYUIOP ASDFGHJKL ZXCVBNM_."; - m_keyLabel[2] = "1234567890 @#%&*-+=' ()[]<>;:,"; + m_keyLabel[1] = "QWERTYUIOP ASDFGHJKL ZXCVBNM-,"; + m_keyLabel[2] = "1234567890 .,:!?/\\\"' ()[]<>_;$"; + m_keyLabel[3] = "1234567890 ()[]{}~|^ @#%&*-+=`"; m_texShiftEmpty = SDLUtils::loadTexture(std::string(RES_PATH) + "/keyboard_shift_empty.png"); m_texShiftFull = SDLUtils::loadTexture(std::string(RES_PATH) + "/keyboard_shift_full.png"); m_texEnter = SDLUtils::loadTexture(std::string(RES_PATH) + "/keyboard_enter.png"); @@ -74,7 +75,7 @@ void Keyboard::render(const bool p_focus) SDLUtils::renderTexture(m_texArrow, m_keyboard.x + m_key[34].x + m_key[34].w / 2, m_keyboard.y + m_key[34].y + m_key[34].h / 2, SDLUtils::T_ALIGN_CENTER, SDLUtils::T_ALIGN_MIDDLE); SDLUtils::renderTexture(m_texArrow, m_keyboard.x + m_key[35].x + m_key[35].w / 2, m_keyboard.y + m_key[35].y + m_key[35].h / 2, SDLUtils::T_ALIGN_CENTER, SDLUtils::T_ALIGN_MIDDLE, SDL_FLIP_HORIZONTAL); // Number / symbols - SDLUtils::renderText(m_keyLabelCurrent == 2 ? "abc" : "&123", g_font, m_keyboard.x + m_key[32].x + m_key[32].w / 2, m_keyboard.y + m_key[32].y + m_key[32].h / 2, {COLOR_TEXT_NORMAL}, getBackgroundColor(32, p_focus), SDLUtils::T_ALIGN_CENTER, SDLUtils::T_ALIGN_MIDDLE); + SDLUtils::renderText(m_keyLabelCurrent == 3 ? "abc" : "&123", g_font, m_keyboard.x + m_key[32].x + m_key[32].w / 2, m_keyboard.y + m_key[32].y + m_key[32].h / 2, {COLOR_TEXT_NORMAL}, getBackgroundColor(32, p_focus), SDLUtils::T_ALIGN_CENTER, SDLUtils::T_ALIGN_MIDDLE); } //------------------------------------------------------------------------------ @@ -117,20 +118,12 @@ void Keyboard::keyPressed(const SDL_Event &event) // Shift else if (m_cursor == 21 || m_cursor == 31) { - if (m_keyLabelCurrent == 1) - m_keyLabelCurrent = 0; - else - m_keyLabelCurrent = 1; - g_hasChanged = true; + keyPressedShift(); } // Symbol else if (m_cursor == 32) { - if (m_keyLabelCurrent == 2) - m_keyLabelCurrent = 0; - else - m_keyLabelCurrent = 2; - g_hasChanged = true; + keyPressedSymbol(); } // Left arrow else if (m_cursor == 34) @@ -258,11 +251,7 @@ void Keyboard::moveCursorUp(const int p_step, bool p_loop) // Page up => symbol button if (p_step > 1) { - if (m_keyLabelCurrent == 2) - m_keyLabelCurrent = 0; - else - m_keyLabelCurrent = 2; - g_hasChanged = true; + keyPressedSymbol(); return; } // 1st line @@ -305,11 +294,7 @@ void Keyboard::moveCursorDown(const int p_step, bool p_loop) // Page down => shift button if (p_step > 1) { - if (m_keyLabelCurrent == 1) - m_keyLabelCurrent = 0; - else - m_keyLabelCurrent = 1; - g_hasChanged = true; + keyPressedShift(); return; } // 1st line @@ -414,3 +399,29 @@ int Keyboard::getKeyboardH(void) { return 2*KEYBOARD_MARGIN + 3*KEYBOARD_KEY_SPACING + 4*getKeyH(); } + +//------------------------------------------------------------------------------ + +// Press symbol button +void Keyboard::keyPressedSymbol(void) +{ + switch (m_keyLabelCurrent) + { + case 2: m_keyLabelCurrent = 3; break; + case 3: m_keyLabelCurrent = 0; break; + default: m_keyLabelCurrent = 2; break; + } + g_hasChanged = true; +} + +//------------------------------------------------------------------------------ + +// Press shift button +void Keyboard::keyPressedShift(void) +{ + if (m_keyLabelCurrent == 1) + m_keyLabelCurrent = 0; + else + m_keyLabelCurrent = 1; + g_hasChanged = true; +} diff --git a/src/keyboard.h b/src/keyboard.h index 1c8840e..a1b09f7 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -46,6 +46,12 @@ class Keyboard : public IWindow // Get background color for the item at the given index virtual SDL_Color getBackgroundColor(const int p_i, const bool p_focus) const; + // Press symbol button + void keyPressedSymbol(void); + + // Press shift button + void keyPressedShift(void); + // Parent window IWindow *m_parent; @@ -56,7 +62,7 @@ class Keyboard : public IWindow SDL_Rect m_key[36]; // Labels for the keys - std::string m_keyLabel[3]; + std::string m_keyLabel[4]; int m_keyLabelCurrent; // Size and coordinates of the keyboard diff --git a/src/textEditor.cpp b/src/textEditor.cpp index 7baa0ca..ce4158e 100644 --- a/src/textEditor.cpp +++ b/src/textEditor.cpp @@ -17,6 +17,8 @@ TextEditor::TextEditor(const std::string &p_title): // Init cursor m_inputTextCursor.x = 0; m_inputTextCursor.y = 0; + // Text selection + unselectText(); // Read file std::ifstream ifs(p_title); if (! ifs.is_open()) @@ -76,16 +78,42 @@ void TextEditor::render(const bool p_focus) l_y += LINE_HEIGHT; SDL_Color l_fgColor = {COLOR_TEXT_NORMAL}; SDL_Color l_bgColor = {COLOR_BODY_BG}; + SDL_Color l_bgColorSelect = {COLOR_CURSOR_FOCUS}; + std::string subLine = ""; + int nbCharPart1 = 0, nbCharPart2 = 0, nbCharPart3 = 0; for (int l_i = m_camera.y; l_i < m_camera.y + m_nbVisibleLines && l_i < m_nbItems; ++l_i, l_y += LINE_HEIGHT) - if (m_camera.x < static_cast(m_lines[l_i].size())) + { + // Case : nothing visible on this line + if (m_camera.x >= static_cast(m_lines[l_i].size())) + continue; + // Case: no text selection + if (m_textSelectionStart.y == -1 || m_textSelectionEnd.y == -1) + { SDLUtils::renderText(m_lines[l_i].substr(m_camera.x, m_nbVisibleChars), g_fontMono, MARGIN_X, l_y, l_fgColor, l_bgColor, SDLUtils::T_ALIGN_LEFT, SDLUtils::T_ALIGN_MIDDLE); + continue; + } + // Case: text selection + subLine = m_lines[l_i].substr(m_camera.x, m_nbVisibleChars); + nbCharPart1 = 0; + nbCharPart2 = 0; + nbCharPart3 = 0; + getNbSelectedChars(l_i, subLine.size(), nbCharPart1, nbCharPart2); + nbCharPart3 = subLine.size() - nbCharPart1 - nbCharPart2; + // Render line in 3 parts : unselected / selected / unselected + if (nbCharPart1 > 0) + SDLUtils::renderText(subLine.substr(0, nbCharPart1), g_fontMono, MARGIN_X, l_y, l_fgColor, l_bgColor, SDLUtils::T_ALIGN_LEFT, SDLUtils::T_ALIGN_MIDDLE); + if (nbCharPart2 > 0 && ! subLine.substr(nbCharPart1, nbCharPart2).empty()) + SDLUtils::renderText(subLine.substr(nbCharPart1, nbCharPart2), g_fontMono, MARGIN_X + nbCharPart1 * g_charW, l_y, l_fgColor, l_bgColorSelect, SDLUtils::T_ALIGN_LEFT, SDLUtils::T_ALIGN_MIDDLE); + if (nbCharPart3 > 0 && ! subLine.substr(nbCharPart1 + nbCharPart2, nbCharPart3).empty()) + SDLUtils::renderText(subLine.substr(nbCharPart1 + nbCharPart2, nbCharPart3), g_fontMono, MARGIN_X + (nbCharPart1 + nbCharPart2) * g_charW, l_y, l_fgColor, l_bgColor, SDLUtils::T_ALIGN_LEFT, SDLUtils::T_ALIGN_MIDDLE); + } // Render cursor SDL_SetRenderDrawColor(g_renderer, COLOR_TEXT_NORMAL, 255); rect.w = 1; - rect.h = LINE_HEIGHT; + rect.h = LINE_HEIGHT - 4; rect.x = MARGIN_X + (m_inputTextCursor.x - m_camera.x) * g_charW; - rect.y = LINE_HEIGHT + (m_inputTextCursor.y - m_camera.y) * LINE_HEIGHT; + rect.y = LINE_HEIGHT + 2 +(m_inputTextCursor.y - m_camera.y) * LINE_HEIGHT; SDL_RenderFillRect(g_renderer, &rect); } @@ -123,11 +151,11 @@ void TextEditor::keyPressed(const SDL_Event &event) dialog.addOption("Quit", 3, g_iconQuit); switch (dialog.execute()) { - case 0: save(); break; - case 1: deleteLine(); break; - case 2: duplicateLine(); break; - case 3: quit(); break; - default: return; + case 0: save(); break; + case 1: deleteLine(); break; + case 2: duplicateLine(); break; + case 3: quit(); break; + default: break; } return; } @@ -140,6 +168,15 @@ void TextEditor::keyPressed(const SDL_Event &event) quit(); return; } + // Button select + if (BUTTON_PRESSED_SELECT) + { + resetTimer(); + unselectText(); + m_textSelectionStart = m_inputTextCursor; + g_hasChanged = true; + return; + } } //------------------------------------------------------------------------------ @@ -148,6 +185,10 @@ void TextEditor::keyPressed(const SDL_Event &event) void TextEditor::moveCursorUp(const int p_step, bool p_loop) { + // Selection = none + if (! BUTTON_HELD_SELECT) + unselectText(); + g_hasChanged = true; if (m_inputTextCursor.y <= 0) return; // Previous line @@ -158,16 +199,21 @@ void TextEditor::moveCursorUp(const int p_step, bool p_loop) m_inputTextCursor.x = m_oldX; if (m_inputTextCursor.x > static_cast(m_lines[m_inputTextCursor.y].size())) m_inputTextCursor.x = m_lines[m_inputTextCursor.y].size(); + // Text selection + if (BUTTON_HELD_SELECT) + m_textSelectionEnd = m_inputTextCursor; // Camera adjustCamera(); // Scrollbar adjustScrollbarPosition(); - // Redraw - g_hasChanged = true; } void TextEditor::moveCursorDown(const int p_step, bool p_loop) { + // Selection = none + if (! BUTTON_HELD_SELECT) + unselectText(); + g_hasChanged = true; if (m_inputTextCursor.y >= static_cast(m_lines.size()) - 1) return; // Next line @@ -178,16 +224,21 @@ void TextEditor::moveCursorDown(const int p_step, bool p_loop) m_inputTextCursor.x = m_oldX; if (m_inputTextCursor.x > static_cast(m_lines[m_inputTextCursor.y].size())) m_inputTextCursor.x = m_lines[m_inputTextCursor.y].size(); + // Text selection + if (BUTTON_HELD_SELECT) + m_textSelectionEnd = m_inputTextCursor; // Camera adjustCamera(); // Scrollbar adjustScrollbarPosition(); - // Redraw - g_hasChanged = true; } void TextEditor::moveCursorLeft(const int p_step, bool p_loop) { + // Selection = none + if (! BUTTON_HELD_SELECT) + unselectText(); + g_hasChanged = true; if (m_inputTextCursor.x <= 0) { if (m_inputTextCursor.y <= 0) @@ -201,16 +252,21 @@ void TextEditor::moveCursorLeft(const int p_step, bool p_loop) --m_inputTextCursor.x; } m_oldX = m_inputTextCursor.x; + // Text selection + if (BUTTON_HELD_SELECT) + m_textSelectionEnd = m_inputTextCursor; // Camera adjustCamera(); // Scrollbar adjustScrollbarPosition(); - // Redraw - g_hasChanged = true; } void TextEditor::moveCursorRight(const int p_step, bool p_loop) { + // Selection = none + if (! BUTTON_HELD_SELECT) + unselectText(); + g_hasChanged = true; if (m_inputTextCursor.x >= static_cast(m_lines[m_inputTextCursor.y].size())) { // Go to the start of next line @@ -224,12 +280,13 @@ void TextEditor::moveCursorRight(const int p_step, bool p_loop) ++m_inputTextCursor.x; } m_oldX = m_inputTextCursor.x; + // Text selection + if (BUTTON_HELD_SELECT) + m_textSelectionEnd = m_inputTextCursor; // Camera adjustCamera(); // Scrollbar adjustScrollbarPosition(); - // Redraw - g_hasChanged = true; } //------------------------------------------------------------------------------ @@ -255,6 +312,9 @@ void TextEditor::adjustCamera(void) // Callbacks for virtual keyboard void TextEditor::keyboardInputChar(const std::string &p_string) { + // Selection = none + unselectText(); + // Insert character m_lines[m_inputTextCursor.y].insert(m_inputTextCursor.x, p_string); ++m_inputTextCursor.x; m_oldX = m_inputTextCursor.x; @@ -265,6 +325,8 @@ void TextEditor::keyboardInputChar(const std::string &p_string) void TextEditor::keyboardInputEnter(void) { + // Selection = none + unselectText(); // Insert new line m_lines.insert(m_lines.begin() + m_inputTextCursor.y + 1, m_lines[m_inputTextCursor.y].substr(m_inputTextCursor.x)); // Cut current line @@ -284,6 +346,14 @@ void TextEditor::keyboardInputEnter(void) void TextEditor::keyboardBackspace(void) { + // Remove selected text if any + if (m_textSelectionStart.y != -1 && m_textSelectionEnd.y != -1 && (m_textSelectionStart.x != m_textSelectionEnd.x || m_textSelectionStart.y != m_textSelectionEnd.y)) + { + removeSelectedText(); + return; + } + unselectText(); + g_hasChanged = true; if (m_inputTextCursor.x <= 0) { if (m_inputTextCursor.y <= 0) @@ -291,25 +361,22 @@ void TextEditor::keyboardBackspace(void) // Move cursor --m_inputTextCursor.y; m_inputTextCursor.x = m_lines[m_inputTextCursor.y].size(); - m_oldX = m_inputTextCursor.x; // Append current line to the previous one m_lines[m_inputTextCursor.y].append(m_lines[m_inputTextCursor.y + 1]); // Remove current line m_lines.erase(m_lines.begin() + m_inputTextCursor.y + 1); m_nbItems = m_lines.size(); - adjustScrollbar(); - m_hasModifications = true; } else { // Remove previous character in the line m_lines[m_inputTextCursor.y].erase(m_inputTextCursor.x - 1, 1); --m_inputTextCursor.x; - m_oldX = m_inputTextCursor.x; - m_hasModifications = true; } + m_oldX = m_inputTextCursor.x; + m_hasModifications = true; + adjustScrollbar(); adjustCamera(); - g_hasChanged = true; } void TextEditor::keyboardMoveLeft(void) @@ -376,6 +443,7 @@ void TextEditor::quit(void) // Delete current line void TextEditor::deleteLine(void) { + unselectText(); m_lines.erase(m_lines.begin() + m_inputTextCursor.y); m_nbItems = m_lines.size(); adjustScrollbar(); @@ -389,6 +457,7 @@ void TextEditor::deleteLine(void) // Duplicate current line void TextEditor::duplicateLine(void) { + unselectText(); m_lines.insert(m_lines.begin() + m_inputTextCursor.y + 1, m_lines[m_inputTextCursor.y]); m_nbItems = m_lines.size(); adjustScrollbar(); @@ -396,3 +465,140 @@ void TextEditor::duplicateLine(void) m_hasModifications = true; g_hasChanged = true; } + +//------------------------------------------------------------------------------ + +// For a line, get the number of unselected and selected chars +void TextEditor::getNbSelectedChars(const int p_lineIndex, const int p_lineSize, int &p_nbUnselected, int &p_nbSelected) +{ + // If start point is after end point, swap them + SDL_Point start, end; + getSortedSelectionPoints(start, end); + // Case: selection starts after or ends before the line + if (start.y > p_lineIndex || end.y < p_lineIndex) + { + p_nbUnselected = p_lineSize; + p_nbSelected = 0; + return; + } + // Case: selection starts before the line and ends after the line + if (start.y < p_lineIndex && end.y > p_lineIndex) + { + p_nbUnselected = 0; + p_nbSelected = p_lineSize; + return; + } + // Case: selection starts at the line and ends after the line + if (start.y == p_lineIndex && end.y > p_lineIndex) + { + p_nbUnselected = start.x - m_camera.x; + if (p_nbUnselected < 0) p_nbUnselected = 0; + else if (p_nbUnselected > p_lineSize) p_nbUnselected = p_lineSize; + p_nbSelected = p_lineSize - p_nbUnselected; + return; + } + // Case: selection starts before the line and ends at the line + if (start.y < p_lineIndex && end.y == p_lineIndex) + { + p_nbUnselected = 0; + p_nbSelected = end.x - m_camera.x; + if (p_nbSelected < 0) p_nbSelected = 0; + else if (p_nbSelected > p_lineSize) p_nbSelected = p_lineSize; + return; + } + // Case: selection starts and ends at the line + if (start.y == p_lineIndex && end.y == p_lineIndex) + { + p_nbUnselected = start.x - m_camera.x; + if (p_nbUnselected < 0) p_nbUnselected = 0; + else if (p_nbUnselected > p_lineSize) p_nbUnselected = p_lineSize; + p_nbSelected = end.x - start.x; + if (start.x < m_camera.x) + p_nbSelected -= m_camera.x - start.x; + if (p_nbSelected < 0) p_nbSelected = 0; + else if (p_nbSelected > p_lineSize) p_nbSelected = p_lineSize; + return; + } +} + +//------------------------------------------------------------------------------ + +// Unselect text +void TextEditor::unselectText(void) +{ + m_textSelectionStart.x = -1; + m_textSelectionStart.y = -1; + m_textSelectionEnd.x = -1; + m_textSelectionEnd.y = -1; +} + +//------------------------------------------------------------------------------ + +// Remove selected text, if any +void TextEditor::removeSelectedText(void) +{ + // If start point is after end point, swap them + SDL_Point start, end; + getSortedSelectionPoints(start, end); + // Remove selected text + for (int indLine = start.y, nbErased = 0; indLine <= end.y; ++indLine) + { + // Case: remove line completely + if ((start.y < indLine || (start.y == indLine && start.x == 0)) && end.y > indLine) + { + m_lines.erase(m_lines.begin() + indLine - nbErased); + ++nbErased; + continue; + } + // Case: remove a part of the line + if (start.y == indLine && end.y == indLine) + { + // Remove only part of the line + m_lines[indLine - nbErased].erase(start.x, end.x - start.x); + continue; + } + // Case: remove end of line + if (start.y == indLine) + m_lines[indLine - nbErased].erase(start.x); + // Case: remove beginning of line + if (end.y == indLine) + { + m_lines[indLine - nbErased].erase(0, end.x); + if (start.y < indLine - nbErased) + { + // Append the rest of the line to the previous line + m_lines[indLine - nbErased - 1].append(m_lines[indLine - nbErased]); + // Remove line + m_lines.erase(m_lines.begin() + indLine - nbErased); + ++nbErased; + } + } + } + // Update everything + m_inputTextCursor = m_textSelectionStart; + m_oldX = m_inputTextCursor.x; + unselectText(); + m_nbItems = m_lines.size(); + m_hasModifications = true; + g_hasChanged = true; + adjustScrollbar(); + adjustCamera(); +} + +//------------------------------------------------------------------------------ + +// Get start and end points, with start < end +void TextEditor::getSortedSelectionPoints(SDL_Point &p_start, SDL_Point &p_end) +{ + if (m_textSelectionStart.y > m_textSelectionEnd.y || (m_textSelectionStart.y == m_textSelectionEnd.y && m_textSelectionStart.x > m_textSelectionEnd.x)) + { + // Flip start and end + p_start = m_textSelectionEnd; + p_end = m_textSelectionStart; + } + else + { + p_start = m_textSelectionStart; + p_end = m_textSelectionEnd; + } +} diff --git a/src/textEditor.h b/src/textEditor.h index db2bedc..80a6548 100644 --- a/src/textEditor.h +++ b/src/textEditor.h @@ -44,6 +44,14 @@ class TextEditor : public IWindow // Adjust camera void adjustCamera(void); + // For a line, get the number of unselected and selected chars + void getNbSelectedChars(const int p_lineIndex, const int p_lineSize, int &p_nbUnselected, int &p_nbSelected); + + // Text selection + void unselectText(void); + void removeSelectedText(void); + void getSortedSelectionPoints(SDL_Point &p_start, SDL_Point &p_end); + // Save file void save(void); @@ -67,6 +75,10 @@ class TextEditor : public IWindow // Has modifications bool m_hasModifications; + + // Start and end for text selection + SDL_Point m_textSelectionStart; + SDL_Point m_textSelectionEnd; }; #endif diff --git a/src/textInput.cpp b/src/textInput.cpp index a78ff4a..77b9a88 100644 --- a/src/textInput.cpp +++ b/src/textInput.cpp @@ -58,7 +58,7 @@ void TextInput::render(const bool p_focus) // Cursor SDL_SetRenderDrawColor(g_renderer, COLOR_TEXT_NORMAL, 255); - SDL_Rect rect = { m_dialogBody.x + MARGIN_X + (m_cursor - m_camera.x) * g_charW, m_dialogBody.y + 3, 1, LINE_HEIGHT - 6 }; + SDL_Rect rect = { m_dialogBody.x + MARGIN_X + (m_cursor - m_camera.x) * g_charW, m_dialogBody.y + 2, 1, LINE_HEIGHT - 4 }; SDL_RenderFillRect(g_renderer, &rect); }