27DROQW2CHKBMWQCCR7N7VK54P3HE7MESZIJSJ32JTPKEE23WJPAC BW6YXB6WOSGAYRJ6KORBBSZS66R6L63D4YYDEYNASWUEBI4IPKCQC HHW3B3WF57ENGJA6D3XCQXUO5S4HN3UP6QNE3C2DOMOTVZAAHXRQC DDXXXXBRUH4UHHPOLAK2IG45C4QAPGSR4MTLV3MVFV3EMND43DIAC NONKKVVPSOFWX3FTCBAI6JC67GK7AVJH4PAHBFPCZQLR3DVLJ2HAC SDVBZT6677IGSC5VLPBAAPPYXSAHEM2ABFYY7I46VXGGCQA5MR5QC BPL2TDWHU2IJNONZZEWNP7A3FMSKBUWXHC6Z4PJSE7QUGCRXAQIAC 4PHDQ5L5N644QYM73IXMNCLAKQELYEPBDFXHTGCTTAKJAR6PEMTAC WCU5H2FEPEEOHFB4HHCLDNRLTCE6KHMRF6WV5RBM4EMWMXQ4LOTAC 7XKWT5Y5LCOI6WHUN67ZYC35NV5JCZOEM6NHUYUCQNQKBJQGTGEAC 23DEB6JLDWF7RH65IRVW2F6ZPR2XCYCR3NZCTSEVG4AACSWJWWJQC GXEM6FP6K3F2ICW4ZOTKRZ6FA4HL6EVCIAGW7PIVEFP4PPHZOKOQC CZB4CK2RB6LQOHUIHCFUGGSNGPRIASYBXX64UEQ3SKLI3TWIA5BQC BU3U7TIJITHHRKBWYFPP3KEXLMVUTMOIA3IRVP4BUZVCAMFKZDFQC NVSWVPW5IGHXNRE2OMV4OEWRFJA25DP37CRFPZEVWAZINWGCCVXAC NUCZBE77AITZNMPHNNHX36HDTO2IVN6YKPZBZHQWKVRGA5BFDTJAC IEHG6OROGLZINLGZACEOD2PHQOM522TDUUF2UT6APHT42GUH2OXAC UEE5W7WJ46FIBN4ZH45Z33L4RYXK5AP5ZIBHYTFOJTDWVVX54QKAC LYN3L74WRXZI4KNNIMNLPRFQ36RAGPWNE2O5AMB42H3CSTI6QM6QC WPW3AVFS3WQVHNSCYVKX7ABWTQUUGVO4SXYCJZT2WOL6TOITX7EQC BZRRUIFQQTGFJZH42H3LI4JX2GPCWVOKYF3HJQO7KNLHHHC7GAWQC VIU2FBNVHG5FV5AJLVPMGEUO5HCLJEGZTRWNY2C5XC4AKMQZZKVAC KICO5EE5UQ2RXGH2PUR553ZB5KXQ6OKJYBPTEVEGO3L373OJWXIQC AVLAYODPMKCDBUFJSTGNUXIK74V3NDCBH55DBBFTNVBMFY6I7BCAC R5QXEHUIZLELJGGCZAE7ATNS3CLRJ7JFRENMGH4XXH24C5WABZDQC CE4LZV4TNXJT54CVGM3QANCBP42TMLMZWF2DBSMUYKAHILXIZEMQC LXTTOB33N2HCUZFIUDRQGGBVHK2HODRG4NBLH6RXRQZDCHF27BSAC 4VKEE43Z7MUPNIAOCK36INVBNHRTSWRRN37TIKRPXPH3DRKGHHAQC EMHRPJ3RAVIVJEQIRXIVDGENV6QHUUGXXRWTJ3BXC7SZNC66VK5QC BULPIBEGL7TMK6CVIE7IS7WGAHGOSUJBGJSFQK542MOWGHP2ADQQC DGK5BPVI6PAD3WK2ZB2ITMBE6WYSU3ZR7TV7RTCQ2WJQ4RGJE5RQC MP2TBKU6CNDMZKENYMBV62F5KQ27ZWEVPVRFS2RESVDQQT2IRR4AC YW2GO3U4JZBBIVZIK3ZVHM7SDDZU3X65VSZOLMWD7TGVPEFJSUYAC 2ZYV7D3W2HPQW2HYB7XDPM4T7KEWPUFPZ77BDLCCDSCLRPJFK6PQC XNFTJHC4QSHNSIWNN7K6QZEZ37GTQYKHS4EPNSVPQCUSWREROGIQC 3TDOZESEOYHGF6LYKR6PYSPNFI3QUGED2BKM5LUDEKJKRIX3ACEAC PX7DDEMOBGPVK3FXKK5XEPG24CJXZSVW67DLG2JZZ5E77NVEAA3AC EQP53UQV3YCW43IDOGQSGA6YTPNRTLCMGHSHUBDZNHNSWLX5WO7AC VJ77YABHVJZWJKLHAGIPC562GYM73AUGRLCP4JLKP5JPWPT2RIHAC IRCKL6VNSFB7TQEKPQUPJCN37N5QW7D54DSZMESVXGK7NEHGSIPAC DHI6IJCNSTHGED67T6H5X6Y636C7PIDGIJD32HBEKLT5WIMRS5MAC AYE2VEGJ63AWWX76SFQZLOTBIZOQRWBG4AZMIOSVOI2WZVRQJXYAC GN3IF4WF352YK5K4YHVMAIMPL7PNTCEMDWW22PTKDOXKV2FZJ7NQC ZPUQSPQPQFVRUIHGLAWW3IDBYODIWDHO62HAC3WWF5TM3CIJGHNQC CPZGQT72EBP3SEDBPDWQRK5IUGA664PHXNP2GOHJLP43PKPWF25AC 5L7K4GBDEAFH44LMLNKVFMHLWDNXXBKRPEI347VE5ZLXVFSMD2FAC ULKLJBN6Q2EXYOXGIJLJ5NZPZD2MQSWR63Z2I3KDYJDAJQA5VNZAC HIKLULFQG7Q7L4C5KXR3DV3TBZ2RGWXBJJXIGSE5YQWF37AJOYZAC VHQCNMARPMNBSIUFLJG7HVK4QGDNPCGNVFLHS3I4IGNVSV5MRLYQC 7M5PGWKUXWBSSBTCGUT7KKMDQW6IDQMSLTQHQO37V45PG65XLQMQC OTIBCAUJ3KDQJLVDN3A536DLZGNRYMGJLORZVR3WLCGXGO6UGO6AC PGZJ6NATSMW4XH64XEPE5Q2EEYCMAMQIIP2OZXPNJ527234QPKMQC AD34IX2ZSGYGU3LGY2IZOZNKD4HRQOYJVG5UWMWLXJZJSM62FFOAC NFCBIEZD5DPQE57TKEMBQCQY4L7R5QSTUPBBITXGREWZB5XBHC3QC 6J3NXBYGADKVHD53QKHUZNRO2B52DC66Y6GQT5KEH6YKVYNCCRTAC 73OCE2MCBJJZZMN2KYPJTBOUCKBZAOQ2QIAMTGCNOOJ2AJAXFT2AC K464QQR4FTXFUMHFWAGOD5DJ6YHUBUKRHLXF2ORE74DVT7TVQ35QC J2SVGR2EQEROXDDMYZOCELD2VDYQALGZYRSZ4WGMTACAGMRPJ7UAC NP7PIUBTR4K6SWJS46YZG3H2RYYNRGNEJMPV4I24TQXT5O3YT27QC Z4XRNDTRTGSZHNB65WNHOVUBFW4QWQABLVSK4RM3QJHGK33DMRJAC AJB4LFRBMIRBEDWJ3OW7GQIMD2BZBVQ62GH4TE2FISWZKSAHRF4QC RF5ALVNYB2FMU7LRRD5LMQC7P6OO4BX3NXIGWNZTQ2CD62RBRRFAC UWNHC4AAO3SPOYLPANTO4WKCTZL7KAYC73Q2YUZFFW7K26FVJ7FQC DLQMM2656JHXX3ONOEM6UIOXKFJFT5QT7RHWK7YS2W77PVZWHRSAC NQKFQSZEFIQTIJXEJ64KX46JXLWUUFXVRTQCPM7HF4DUHT2QHZAAC 4ZM74KYLE3HXVMSD335YVJ7BYXQSQGWIJ2ATV6MTQSEWSFVBKXOQC 4J2WLDRMP76H4ZFRQR244KZNOUDN3VSLFBFHI3GSCGKKWA3LNKJQC QKAMUWSB6GWKEGLXFKALGCIU7HBTZ4YGLIR7TLA6ZZCUK7WNCNUQC RT6EV6OPUYCXYZOX2PHFXJ7KT77KHNEVINEGQXIQLHQVKPGTN6VQC KVHUFUFVOSY6GB4XI2QK4T4WCLIYOV3NZR67TX6AQHAQDWJMEOBQC AVTNUQYRBW7IX2YQ3KDLVQ23RGW3BAKTAE7P73ASBYNKOHMQMH5AC ZUOL7X6VIPRCMEZURYGNHTDEIP3ZCHZW4PKVKBNXVZL5V4VOE5ZQC 7IKRRESBHMYHHKW4XHUEEKHKPOBLAGZ7A7FJMRU32MTRKIV6S7GQC RMKMPFT5L67WIFWIO4GTC6XESX6UPKNL4GPNQLOBC5CXSUZABEHQC FYS7TCDWKNRNOJSGRD2JMU4B2LHX5S63ZISM7YF7KZYEYLVCIKIAC 2INHXC3KRJVZTX2BQ63ZQLHIC5SWPUG4PQKCMLC7SQKN5R7LJZ6QC 2ENZW7TVCS47BWCA4AIEVGKGMT4Y2TSM5IJ7O5K2VSWNXIN3SG4QC 3GFQP6IRHABYMDAEXEMM2HQNEUY4LT2P72PI3KXV4M6PSQT3SFLAC CCYSVZA2ONWXB6XJXWSIEBY4CS2LGBEVV3RB6KZ6I4XYRXQLSTXQC BYG5CEMVXANDTBI2ORNVMEY6K3EBRIHZHS4QBK27VONJC5537COQC JCSLDGAH2F6AIY4Z6XM6K4LOMW7EFY3E4NF5YXLMHLTYTX3A4Z3QC OGUV4HSA7XGSQLUVWBAE3AE263Z7Z6G3BZOB4CN2AOYD2DEJMOZAC LS55YKGWKICTQTAHR5KLMNDOL6CDI4ATT3NT5Z2YL5IM3CRQOONQC NQWWTGXRLSBASOSP75FPOSVYP664VYRFQH7MY5LALLIP2VEBQMCQC IDG26SXKRKPRUQM3G2MMBQR3UZGNU7NCWJBBDKKIM5IGUNJQ2URQC HRWN5V6J6VMXS7WNSRGI7WMUSZ2OI52JJ4IK352VVSDZI4EF5HHQC SGMDI4TCL375Y5ADXK6KDMWADDRXHZMCJ42PBMMW3RLMNDABEPUQC HOSPP2ANSW654DYRTC6CQUQA2GUKV6T2FI7QBKXD2DZS3R32IMGAC WTDKUACNTWB4KD34TZZNPILNX4FQ6MR64XYBAA5GOMICF73WLIAAC OLZRJ4AXIXZHJSCTMH365Z6HPE26UAVSXPSFAPASZPPHT44VYL4AC BERHYBXMPLRJKHXKCHGIMURTVGGE2FLF5JZPWR5WBVEF44DISIHQC GY6LTMIJSZCHAPP4BFD36DOXCCOF25YWYV6CO7YFUAXQOJRETOLAC B4YZWV6SQI6HK4PZAUKB5L6TISNECL72GFZZET34Q673OVN7IBRAC 7CLGG7J277QZGMNOVFEXBX6DRETCVK7GH66HJ7BYOBMPHTJCDFMAC K2X6G75Z6XBC4DVIRWC5HC7XA3A2SKOM3MWSQTCFEYWIJL7LME2QC OWK3U6VDHPZM6Q6MB7PVFZPDD2KD5NJ3WHVMGTQ2XGUNYDNWSPWAC 42LVB4DEK3ILS3O5DHFMTJO5HNMJFDYA2WRCLUIOYFPA46MJFZTAC L6XA5EY2FVDQFRGCBFSCOM6O4GYN74K3YTZKGFUOPXIUYA3YT5JQC Y4VYNEGFA3RYG5TR75B3FTVU6DITIS3TQDCOOSYSIUG5NBFEYM6QC KAUD3YIKPOXHIUZVR3VCIQHQGBPWTBHXEXC3VQIPAN2BAV6SEMIQC T7SJSJIH3FUWK2TK6DNVLCNYL7ROJGFVMOOCIY3L46EX5T7M7VNAC 7DYUAOI6WHAP75T2KEGN6CPSASO7B6L6BDE6FQ5ELND7T6X3WO4AC 4AXV2HG4NMAHAWGWD35V5PXULNORCBEKY65UQT37XNYXCSB7TWEAC BLWAYPKV3MLDZ4ALXLUJ25AIR6PCIL4RFYNRYLB26GFVC2KQBYBAC F63Q4OV73CQC6WTWDCURANYMF2PM4TJCXWF3FZ25X4QY7ZTEZ6QAC SRVDX4I5QKWAH3Y5DX25PG34U7NY55H46ZYG2APH47BUZT3EJ2HAC 6DE7RBZ6RHNEICJ7EUMCTROK43LW4LYINULIF2QEQOKCXWLUYUXAC IHHNPJ5QIEYWJTC34GSVWJ7KSHAEO7RQCQULTA7MA5RUMQ2GVOZQC W7JMT5V2ELDFZG354LUL5AR6IQLIYQUDXBEPDNZ2BEBXDCZLQJTAC 6VQIWTQUH43LLCBSGL25WJMZWG6T5SMVU6YJC7PSTTZTO5XPOCSQC 2MA33THZH2DRPD7TYP7YXIUKR5E6BAH2BF452TPWYKXMS5I5JRUQC WDMPH4ANFQ4YDIBCKDE5ZSRRNIJFBR5W5CH4VYYFKWS5Q63KHLFAC DRFE3B3ZKRG4RY2R5Q3SDFD3LH4EXUX3CZCDFBNAXVI2SLDS57PAC 3QNOKBFMKBGXBVJIRHR2444JRRMBTABHE4674NR3DT67RRM2X6GAC ZLJGZYQGQ2S4UFWTVF4PQDSGMP6A4IS4GDHCMBAAA5SK2N2NWR3QC D4FEFHQCSILZFQ5VLWNXAIRZNUMCDNGJSM4UJ6T6FDMMIWYRYILQC FS2ITYYHBLFT66YUC3ENPFYI2HOYHOVEPQIN7NQR6KF5MEK4NKZAC IDGP4BJZTKAD6ZO4RLAWYVN6IFCMIM76G6HJGPTE27K4D6CDBUHQC ZRKTXF4QSO22OGFPJZOBNCMOWLFCWHK6IMY2UCID3HCGVMJSDDFAC LGD2F7UV6QWAKLM7JWBKRPUD3AJAUFQ7DZN2E6SBBGXUTS7CGHVQC YHB3IX5ORIPVVQ2C64GK3GZALEMFSJTNU5CPQJCLWY2ZXS7LNHZQC 66X36NZNEHWWURKSZ6G3XSC4CKQ7NTR4HYGDJGLHAUELMUAQC34AC BJ5X5O4ACBBJ56LRBBSTCW6IBQP4HAEOOOPNH3SKTA4F66YTOIDAC function test_resize_window()io.write('\ntest_resize_window')Filename = 'foo'App.screen.init{width=Margin_left+300, height=300}check_eq(App.screen.width, Margin_left+300, 'F - test_resize_window/baseline/width')check_eq(App.screen.height, 300, 'F - test_resize_window/baseline/height')App.resize(200, 400)check_eq(App.screen.width, 200, 'F - test_resize_window/width')check_eq(App.screen.height, 400, 'F - test_resize_window/height')-- TODO: how to make assertions about when App.update got past the early exit?endfunction test_adjust_line_width()io.write('\ntest_adjust_line_width')Filename = 'foo'App.screen.init{width=Margin_left+300, height=300}Line_width = 256App.draw() -- initialize button-- no change for some timeApp.wait_fake_time(0.01)App.update(0)check_eq(Line_width, 256, 'F - test_adjust_line_width/early')-- after 0.1s the change takesApp.wait_fake_time(0.1)App.update(0)check_eq(Line_width, 200, 'F - test_adjust_line_width')endApp.run_after_mouse_press(256, Margin_top-3, 1)App.mouse_move(200, 37)
function test_edit_after_click_resets_selection()io.write('\ntest_edit_after_click_resets_selection')-- display a line of textApp.screen.init{width=80, height=80}Lines = load_array{'abc'}Line_width = 75Cursor1 = {line=1, pos=1}Screen_top1 = {line=1, pos=1}Screen_bottom1 = {}App.draw()-- click past the end of it and hit enterApp.run_after_mouse_click(Margin_left+40,Margin_top+5, 1)check(Selection1.line, 'F - test_edit_after_click_resets_selection/baseline')App.run_after_keychord('return')-- selection is reset since shift key is not pressedcheck_nil(Selection1.line, 'F - test_edit_after_click_resets_selection')end
function Text.offset(s, pos1)if pos1 == 1 then return 1 endlocal result = utf8.offset(s, pos1)if result == nil thenprint(Cursor1.line, Cursor1.pos, #Lines[Cursor1.line].data, Lines[Cursor1.line].data)print(pos1, #s, s)endassert(result)return resultend
-- line-width indicatorbutton('line-width', {x=Line_width-4,y=Margin_top-10, w=10,h=10, color={1,1,1},icon = icon.line_width,onpress1 = function() Line_width_hover = App.getTime() end,})
endend-- update Line_width with some hysteresis while the indicator is draggedif Line_width_hover thenif App.getTime() - Line_width_hover > 0.1 thenLine_width = App.mouse_x()Text.redraw_all()if App.mouse_down(1) thenLine_width_hover = App.getTime()elseLine_width_hover = nilend
function icon.line_width(x, y)love.graphics.setColor(0.7,0.7,0.7)love.graphics.line(x+0,y+0, x+9,y+0)love.graphics.line(x+0,y+1, x+9,y+1)love.graphics.line(x+0,y+2, x+9,y+2)love.graphics.line(x+0,y+3, x+9,y+3)love.graphics.line(x+0,y+4, x+9,y+4)love.graphics.line(x+0,y+5, x+9,y+5)love.graphics.line(x+1,y+6, x+8,y+6)love.graphics.line(x+2,y+7, x+7,y+7)love.graphics.line(x+3,y+8, x+6,y+8)love.graphics.line(x+4,y+9, x+5,y+9)end
love.graphics.print("* Press 'ctrl+s' to switch to drawing squares", Margin_left+30,y)love.graphics.print("* Press 'ctrl+=' or 'ctrl+-' to zoom in or out, ctrl+0 to reset zoom", Margin_left+30,y)
love.graphics.print('* Release the mouse button to finish drawing the polygon', Margin_left+30,y)love.graphics.print("* Press 'p' to add a vertex to the polygon", Margin_left+30,y)
elseif Current_drawing_mode == 'rectangle' thenif #drawing.pending.vertices < 2 thenlove.graphics.print("* Press 'p' to add a vertex to the rectangle", Margin_left+30,y)y = y + Line_heightelselove.graphics.print('* Release the mouse button to finish drawing the rectangle', Margin_left+30,y)y = y + Line_heightlove.graphics.print("* Press 'p' to replace the second vertex of the rectangle", Margin_left+30,y)y = y + Line_heightendelseif Current_drawing_mode == 'square' thenif #drawing.pending.vertices < 2 thenlove.graphics.print("* Press 'p' to add a vertex to the square", Margin_left+30,y)y = y + Line_heightelselove.graphics.print('* Release the mouse button to finish drawing the square', Margin_left+30,y)y = y + Line_heightlove.graphics.print("* Press 'p' to replace the second vertex of the square", Margin_left+30,y)y = y + Line_heightend
endfunction test_move_point_on_manhattan_line()io.write('\ntest_move_point_on_manhattan_line')-- create a drawing with a manhattan lineFilename = 'foo'App.screen.init{width=Margin_left+300, height=300}Lines = load_array{'```lines', '```', ''}Line_width = 256 -- drawing coordinates 1:1 with pixelsCurrent_drawing_mode = 'manhattan'App.draw()App.run_after_mouse_press(Margin_left+5, Margin_top+Drawing_padding_top+6, 1)App.run_after_mouse_release(Margin_left+35, Margin_top+Drawing_padding_top+46, 1)local drawing = Lines[1]check_eq(#drawing.shapes, 1, 'F - test_move_point_on_manhattan_line/baseline/#shapes')check_eq(#drawing.points, 2, 'F - test_move_point_on_manhattan_line/baseline/#points')check_eq(drawing.shapes[1].mode, 'manhattan', 'F - test_move_point_on_manhattan_line/baseline/shape:1')App.draw()-- enter 'move' modeApp.run_after_keychord('C-u')check_eq(Current_drawing_mode, 'move', 'F - test_move_point_on_manhattan_line/mode:1')-- move pointApp.mouse_move(Margin_left+26, Margin_top+Drawing_padding_top+44)App.update(0.05)-- line is no longer manhattancheck_eq(drawing.shapes[1].mode, 'line', 'F - test_move_point_on_manhattan_line/baseline/shape:1')
endendfunction Drawing.relax_constraints(drawing, p)for _,shape in ipairs(drawing.shapes) doif shape.mode == 'manhattan' thenif shape.p1 == p thenshape.mode = 'line'elseif shape.p2 == p thenshape.mode = 'line'endelseif shape.mode == 'rectangle' or shape.mode == 'square' thenfor _,v in ipairs(shape.vertices) doif v == p thenshape.mode = 'polygon'endendend
drawing.pending.p1 = drawing.pending.centerenddrawing.pending.mode = 'manhattan'elseif chord == 'C-m' and not App.mouse_down(1) thenCurrent_drawing_mode = 'manhattan'elseif App.mouse_down(1) and chord == 'l' thenCurrent_drawing_mode = 'line'local _,drawing = Drawing.current_drawing()if drawing.pending.mode == 'freehand' thendrawing.pending.p1 = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)elseif drawing.pending.mode == 'polygon' or drawing.pending.mode == 'rectangle' or drawing.pending.mode == 'square' thendrawing.pending.p1 = drawing.pending.vertices[1]elseif drawing.pending.mode == 'circle' or drawing.pending.mode == 'arc' thendrawing.pending.p1 = drawing.pending.centerenddrawing.pending.mode = 'line'elseif chord == 'C-l' and not App.mouse_down(1) thenCurrent_drawing_mode = 'line'elseif App.mouse_down(1) and chord == 'm' thenCurrent_drawing_mode = 'manhattan'local drawing = Drawing.select_drawing_at_mouse()if drawing.pending.mode == 'freehand' thendrawing.pending.p1 = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)elseif drawing.pending.mode == 'line' then-- do nothingelseif drawing.pending.mode == 'polygon' or drawing.pending.mode == 'rectangle' or drawing.pending.mode == 'square' thendrawing.pending.p1 = drawing.pending.vertices[1]elseif drawing.pending.mode == 'circle' or drawing.pending.mode == 'arc' then