TerryCavanagh / VVVVVV

The source code to VVVVVV! http://thelettervsixtim.es/
Other
7k stars 559 forks source link

Refactor script text input #955

Open AllyTally opened 1 year ago

AllyTally commented 1 year ago

Changes

This PR adds an input system with selection, copying, pasting, and all of that fun stuff, to the script editor.

NOTE: I'm still new to text input, so if someone else sees issues then feel free to contribute.

Legal Stuff:

By submitting this pull request, I confirm that...

InfoTeddy commented 1 year ago

Here's a proof-of-concept for drawing the selection box and cursor with centered text (it's just placing the base x-coordinate at the center point and subtracting an offset). The only issue is that moving between lines is still treated as left-aligned and not based on how the text visually looks. With this, you should be able to get the new input working for level descriptions. It can even be trivially adapted to support right-aligned text, too.

diff --git a/desktop_version/src/Editor.cpp b/desktop_version/src/Editor.cpp
index 79fefb51..aa19cf4b 100644
--- a/desktop_version/src/Editor.cpp
+++ b/desktop_version/src/Editor.cpp
@@ -1571,7 +1571,7 @@ void editorrender(void)
             info.visible_lines = 200 / font::height(PR_FONT_LEVEL);
             info.visible_padding = 48 / font::height(PR_FONT_LEVEL);

-            TextInput::draw_text(PR_FONT_LEVEL | PR_CJK_LOW, 16, 20, &ed.script_buffer, info);
+            TextInput::draw_text(PR_CEN | PR_FONT_LEVEL | PR_CJK_LOW, -1, 20, &ed.script_buffer, info);
             break;
         }
         default:
diff --git a/desktop_version/src/TextInput.cpp b/desktop_version/src/TextInput.cpp
index 400e5180..ddf74cab 100644
--- a/desktop_version/src/TextInput.cpp
+++ b/desktop_version/src/TextInput.cpp
@@ -4,6 +4,7 @@
 #include <string>
 #include <vector>

+#include "Constants.h"
 #include "Font.h"
 #include "Graphics.h"
 #include "KeyPoll.h"
@@ -776,6 +777,11 @@ namespace TextInput
         const int visible_lines = info.visible_lines;
         const int visible_padding = info.visible_padding;

+        if ((flags & PR_CEN) && text_x == -1)
+        {
+            text_x = SCREEN_WIDTH_PIXELS / 2;
+        }
+
         if (cursor_pos.y < display_offset + visible_padding)
         {
             display_offset = SDL_max(0, TextInput::cursor_pos.y - visible_padding);
@@ -792,7 +798,12 @@ namespace TextInput
         {
             if (i + display_offset < (int) text->size())
             {
-                font::print(flags, text_x, text_y + (i * font_height), text->at(i + display_offset), text_color.r, text_color.g, text_color.b);
+                int align_offset = 0;
+                if (flags & PR_CEN)
+                {
+                    align_offset = font::len(flags, text->at(i + display_offset).c_str()) / 2;
+                }
+                font::print(flags & ~PR_CEN, text_x - align_offset, text_y + (i * font_height), text->at(i + display_offset), text_color.r, text_color.g, text_color.b);
             }
         }

@@ -813,9 +824,14 @@ namespace TextInput

                 char* offset_x = UTF8_substr(text->at(rect.y).c_str(), 0, rect.x);
                 char* cut_string = UTF8_substr(text->at(rect.y).c_str(), rect.x, rect.x2);
+                int align_offset = 0;
+                if (flags & PR_CEN)
+                {
+                    align_offset = font::len(flags, text->at(rect.y).c_str()) / 2;
+                }

-                graphics.fill_rect(text_x + font::len(flags, offset_x), text_y + (y - display_offset) * font_height, font::len(flags, cut_string), font_height, text_color);
-                font::print(flags, text_x + font::len(flags, offset_x), text_y + (rect.y2 - display_offset) * font_height, cut_string, selected_color.r, selected_color.g, selected_color.b);
+                graphics.fill_rect(text_x + font::len(flags, offset_x) - align_offset, text_y + (y - display_offset) * font_height, font::len(flags, cut_string), font_height, text_color);
+                font::print(flags & ~PR_CEN, text_x + font::len(flags, offset_x) - align_offset, text_y + (rect.y2 - display_offset) * font_height, cut_string, selected_color.r, selected_color.g, selected_color.b);

                 SDL_free(offset_x);
                 SDL_free(cut_string);
@@ -829,9 +845,14 @@ namespace TextInput
                     const char* line = text->at(rect.y).c_str();
                     char* offset_x = UTF8_substr(line, 0, rect.x);
                     char* selection_w = UTF8_substr(line, rect.x, UTF8_total_codepoints(line));
+                    int align_offset = 0;
+                    if (flags & PR_CEN)
+                    {
+                        align_offset = font::len(flags, line) / 2;
+                    }

-                    graphics.fill_rect(text_x + font::len(flags, offset_x), text_y + (rect.y - display_offset) * font_height, SDL_max(font::len(PR_FONT_LEVEL, selection_w), 1), font_height, text_color);
-                    font::print(flags, text_x + font::len(flags, offset_x), text_y + (rect.y - display_offset) * font_height, selection_w, selected_color.r, selected_color.g, selected_color.b);
+                    graphics.fill_rect(text_x + font::len(flags, offset_x) - align_offset, text_y + (rect.y - display_offset) * font_height, SDL_max(font::len(PR_FONT_LEVEL, selection_w), 1), font_height, text_color);
+                    font::print(flags & ~PR_CEN, text_x + font::len(flags, offset_x) - align_offset, text_y + (rect.y - display_offset) * font_height, selection_w, selected_color.r, selected_color.g, selected_color.b);

                     SDL_free(offset_x);
                     SDL_free(selection_w);
@@ -843,9 +864,14 @@ namespace TextInput
                     if (local_y >= 0 && local_y < visible_lines)
                     {
                         const int line_width = SDL_max(font::len(flags, text->at(rect.y + i).c_str()), 1);
+                        int align_offset = 0;
+                        if (flags & PR_CEN)
+                        {
+                            align_offset = font::len(flags, text->at(rect.y + i).c_str()) / 2;
+                        }

-                        graphics.fill_rect(text_x, text_y + local_y * font_height, line_width, font_height, text_color);
-                        font::print(flags, text_x, text_y + local_y * font_height, text->at(rect.y + i).c_str(), selected_color.r, selected_color.g, selected_color.b);
+                        graphics.fill_rect(text_x - align_offset, text_y + local_y * font_height, line_width, font_height, text_color);
+                        font::print(flags & ~PR_CEN, text_x - align_offset, text_y + local_y * font_height, text->at(rect.y + i).c_str(), selected_color.r, selected_color.g, selected_color.b);
                     }
                 }

@@ -854,9 +880,14 @@ namespace TextInput
                     const char* line_2 = text->at(rect.y2).c_str();
                     char* selection_w = UTF8_substr(line_2, 0, rect.x2);
                     const int line_width = SDL_max(font::len(flags, selection_w), 1);
+                    int align_offset = 0;
+                    if (flags & PR_CEN)
+                    {
+                        align_offset = font::len(flags, text->at(rect.y2).c_str()) / 2;
+                    }

-                    graphics.fill_rect(text_x, text_y + (rect.y2 - display_offset) * font_height, line_width, font_height, text_color);
-                    font::print(flags, text_x, text_y + (rect.y2 - display_offset) * font_height, selection_w, selected_color.r, selected_color.g, selected_color.b);
+                    graphics.fill_rect(text_x - align_offset, text_y + (rect.y2 - display_offset) * font_height, line_width, font_height, text_color);
+                    font::print(flags & ~PR_CEN, text_x - align_offset, text_y + (rect.y2 - display_offset) * font_height, selection_w, selected_color.r, selected_color.g, selected_color.b);

                     SDL_free(selection_w);
                 }
@@ -867,17 +898,22 @@ namespace TextInput
         if (TextInput::flash_timer < 15)
         {
             char* substr = UTF8_substr(text->at(TextInput::cursor_pos.y).c_str(), 0, TextInput::cursor_pos.x);
+            int align_offset = 0;
+            if (flags & PR_CEN)
+            {
+                align_offset = font::len(flags, text->at(TextInput::cursor_pos.y).c_str()) / 2;
+            }

             if (TextInput::cursor_pos.x < (int) text->at(TextInput::cursor_pos.y).size() || TextInput::selecting)
             {
                 graphics.set_color(text_color);
-                int x = text_x + font::len(flags, substr);
+                int x = text_x + font::len(flags, substr) - align_offset;
                 int y = text_y + ((TextInput::cursor_pos.y - display_offset) * font_height);
                 SDL_RenderDrawLine(gameScreen.m_renderer, x, y, x, y + font_height - 1);
             }
             else
             {
-                font::print(flags, text_x + font::len(flags, substr), text_y + ((TextInput::cursor_pos.y - display_offset) * font_height), "_", text_color.r, text_color.g, text_color.b);
+                font::print(flags & ~PR_CEN, text_x + font::len(flags, substr) - align_offset, text_y + ((TextInput::cursor_pos.y - display_offset) * font_height), "_", text_color.r, text_color.g, text_color.b);
             }
             SDL_free(substr);
         }
NyakoFox commented 3 months ago

note to self: apparently this breaks terminals/script boxes making new scripts, though a fix is simple (stop using key.keybuffer in input_submitted())

InfoTeddy commented 3 weeks ago

Conflicts need to be resolved.