about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2022-06-09 15:49:16 -0700
committerKartik K. Agaram <vc@akkartik.com>2022-06-09 15:49:16 -0700
commit6ba10b4de61f1bce61bb946a0d023cf4969fdefe (patch)
treecf271d6c6210ddf00ec145c48544c411f1604b13
parentfa5bf1218af8d87193f5d333904708a312ff7471 (diff)
downloadtext.love-6ba10b4de61f1bce61bb946a0d023cf4969fdefe.tar.gz
fix a corner case when selecting text
The hard part here is keeping click-drag selection working (without
pressing and holding shift).
-rw-r--r--main.lua30
-rw-r--r--text_tests.lua30
2 files changed, 51 insertions, 9 deletions
diff --git a/main.lua b/main.lua
index b318fb8..24d6f00 100644
--- a/main.lua
+++ b/main.lua
@@ -55,6 +55,7 @@ Cursor1 = {line=1, pos=1}  -- position of cursor
 Screen_bottom1 = {line=1, pos=1}  -- position of start of screen line at bottom of screen
 
 Selection1 = {}
+Old_cursor1, Old_selection1, Mousepress_shift = nil  -- some extra state to compute selection between mousepress and mouserelease
 Recent_mouse = {}  -- when selecting text, avoid recomputing some state on every single frame
 
 Cursor_x, Cursor_y = 0, 0  -- in pixels
@@ -271,13 +272,19 @@ function App.mousepressed(x,y, mouse_button)
   for line_index,line in ipairs(Lines) do
     if line.mode == 'text' then
       if Text.in_line(line, x,y) then
-        if App.shift_down() then
-          Selection1 = {line=Cursor1.line, pos=Cursor1.pos}
-        end
-        Cursor1 = {line=line_index, pos=Text.to_pos_on_line(line, x, y)}
-        if not App.shift_down() then
-          Selection1 = {line=Cursor1.line, pos=Cursor1.pos}
-        end
+        -- delicate dance between cursor, selection and old cursor
+        -- manual tests:
+        --  regular press+release: sets cursor, clears selection
+        --  shift press+release:
+        --    sets selection to old cursor if not set otherwise leaves it untouched
+        --    sets cursor
+        --  press and hold to start a selection: sets selection on press, cursor on release
+        --  press and hold, then press shift: ignore shift
+        --    i.e. mousereleased should never look at shift state
+        Old_cursor1 = Cursor1
+        Old_selection1 = Selection1
+        Mousepress_shift = App.shift_down()
+        Selection1 = {line=line_index, pos=Text.to_pos_on_line(line, x, y)}
       end
     elseif line.mode == 'drawing' then
       if Drawing.in_drawing(line, x, y) then
@@ -296,9 +303,14 @@ function App.mousereleased(x,y, button)
       if line.mode == 'text' then
         if Text.in_line(line, x,y) then
           Cursor1 = {line=line_index, pos=Text.to_pos_on_line(line, x, y)}
-          if Text.eq1(Cursor1, Selection1) and not App.shift_down() then
-            Selection1 = {}
+          if Mousepress_shift then
+            if Old_selection1.line == nil then
+              Selection1 = Old_cursor1
+            else
+              Selection1 = Old_selection1
+            end
           end
+          Old_cursor1, Old_selection1, Mousepress_shift = nil
         end
       end
     end
diff --git a/text_tests.lua b/text_tests.lua
index 85b301a..ab7ac10 100644
--- a/text_tests.lua
+++ b/text_tests.lua
@@ -224,6 +224,36 @@ function test_select_text_using_mouse_and_shift()
   check_eq(Cursor1.pos, 4, 'F - test_select_text_using_mouse_and_shift/cursor:pos')
 end
 
+function test_select_text_repeatedly_using_mouse_and_shift()
+  io.write('\ntest_select_text_repeatedly_using_mouse_and_shift')
+  App.screen.init{width=50, height=60}
+  Lines = load_array{'abc', 'def', 'xyz'}
+  Line_width = App.screen.width
+  Cursor1 = {line=1, pos=1}
+  Screen_top1 = {line=1, pos=1}
+  Screen_bottom1 = {}
+  Selection1 = {}
+  App.draw()  -- populate line.y for each line in Lines
+  local screen_left_margin = 25  -- pixels
+  -- click on first location
+  App.run_after_mousepress(screen_left_margin+8,Margin_top+5, '1')
+  App.run_after_mouserelease(screen_left_margin+8,Margin_top+5, '1')
+  -- hold down shift and click on a second location
+  App.keypress('lshift')
+  App.run_after_mousepress(screen_left_margin+20,Margin_top+5, '1')
+  App.run_after_mouserelease(screen_left_margin+20,Margin_top+Line_height+5, '1')
+  -- hold down shift and click at a third location
+  App.keypress('lshift')
+  App.run_after_mousepress(screen_left_margin+20,Margin_top+5, '1')
+  App.run_after_mouserelease(screen_left_margin+8,Margin_top+Line_height+5, '1')
+  App.keyrelease('lshift')
+  -- selection is between first and third location. forget the second location, not the first.
+  check_eq(Selection1.line, 1, 'F - test_select_text_repeatedly_using_mouse_and_shift/selection:line')
+  check_eq(Selection1.pos, 2, 'F - test_select_text_repeatedly_using_mouse_and_shift/selection:pos')
+  check_eq(Cursor1.line, 2, 'F - test_select_text_repeatedly_using_mouse_and_shift/cursor:line')
+  check_eq(Cursor1.pos, 2, 'F - test_select_text_repeatedly_using_mouse_and_shift/cursor:pos')
+end
+
 function test_pagedown()
   io.write('\ntest_pagedown')
   App.screen.init{width=120, height=45}