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?
end
function test_adjust_line_width()
io.write('\ntest_adjust_line_width')
Filename = 'foo'
App.screen.init{width=Margin_left+300, height=300}
Line_width = 256
App.draw() -- initialize button
-- no change for some time
App.wait_fake_time(0.01)
App.update(0)
check_eq(Line_width, 256, 'F - test_adjust_line_width/early')
-- after 0.1s the change takes
App.wait_fake_time(0.1)
App.update(0)
check_eq(Line_width, 200, 'F - test_adjust_line_width')
end
App.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 text
App.screen.init{width=80, height=80}
Lines = load_array{'abc'}
Line_width = 75
Cursor1 = {line=1, pos=1}
Screen_top1 = {line=1, pos=1}
Screen_bottom1 = {}
App.draw()
-- click past the end of it and hit enter
App.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 pressed
check_nil(Selection1.line, 'F - test_edit_after_click_resets_selection')
end
function Text.offset(s, pos1)
if pos1 == 1 then return 1 end
local result = utf8.offset(s, pos1)
if result == nil then
print(Cursor1.line, Cursor1.pos, #Lines[Cursor1.line].data, Lines[Cursor1.line].data)
print(pos1, #s, s)
end
assert(result)
return result
end
-- line-width indicator
button('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,
})
end
end
-- update Line_width with some hysteresis while the indicator is dragged
if Line_width_hover then
if App.getTime() - Line_width_hover > 0.1 then
Line_width = App.mouse_x()
Text.redraw_all()
if App.mouse_down(1) then
Line_width_hover = App.getTime()
else
Line_width_hover = nil
end
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' then
if #drawing.pending.vertices < 2 then
love.graphics.print("* Press 'p' to add a vertex to the rectangle", Margin_left+30,y)
y = y + Line_height
else
love.graphics.print('* Release the mouse button to finish drawing the rectangle', Margin_left+30,y)
y = y + Line_height
love.graphics.print("* Press 'p' to replace the second vertex of the rectangle", Margin_left+30,y)
y = y + Line_height
end
elseif Current_drawing_mode == 'square' then
if #drawing.pending.vertices < 2 then
love.graphics.print("* Press 'p' to add a vertex to the square", Margin_left+30,y)
y = y + Line_height
else
love.graphics.print('* Release the mouse button to finish drawing the square', Margin_left+30,y)
y = y + Line_height
love.graphics.print("* Press 'p' to replace the second vertex of the square", Margin_left+30,y)
y = y + Line_height
end
end
function test_move_point_on_manhattan_line()
io.write('\ntest_move_point_on_manhattan_line')
-- create a drawing with a manhattan line
Filename = 'foo'
App.screen.init{width=Margin_left+300, height=300}
Lines = load_array{'```lines', '```', ''}
Line_width = 256 -- drawing coordinates 1:1 with pixels
Current_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' mode
App.run_after_keychord('C-u')
check_eq(Current_drawing_mode, 'move', 'F - test_move_point_on_manhattan_line/mode:1')
-- move point
App.mouse_move(Margin_left+26, Margin_top+Drawing_padding_top+44)
App.update(0.05)
-- line is no longer manhattan
check_eq(drawing.shapes[1].mode, 'line', 'F - test_move_point_on_manhattan_line/baseline/shape:1')
end
end
function Drawing.relax_constraints(drawing, p)
for _,shape in ipairs(drawing.shapes) do
if shape.mode == 'manhattan' then
if shape.p1 == p then
shape.mode = 'line'
elseif shape.p2 == p then
shape.mode = 'line'
end
elseif shape.mode == 'rectangle' or shape.mode == 'square' then
for _,v in ipairs(shape.vertices) do
if v == p then
shape.mode = 'polygon'
end
end
end
drawing.pending.p1 = drawing.pending.center
end
drawing.pending.mode = 'manhattan'
elseif chord == 'C-m' and not App.mouse_down(1) then
Current_drawing_mode = 'manhattan'
elseif App.mouse_down(1) and chord == 'l' then
Current_drawing_mode = 'line'
local _,drawing = Drawing.current_drawing()
if drawing.pending.mode == 'freehand' then
drawing.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' then
drawing.pending.p1 = drawing.pending.vertices[1]
elseif drawing.pending.mode == 'circle' or drawing.pending.mode == 'arc' then
drawing.pending.p1 = drawing.pending.center
end
drawing.pending.mode = 'line'
elseif chord == 'C-l' and not App.mouse_down(1) then
Current_drawing_mode = 'line'
elseif App.mouse_down(1) and chord == 'm' then
Current_drawing_mode = 'manhattan'
local drawing = Drawing.select_drawing_at_mouse()
if drawing.pending.mode == 'freehand' then
drawing.pending.p1 = Drawing.insert_point(drawing.points, drawing.pending.points[1].x, drawing.pending.points[1].y)
elseif drawing.pending.mode == 'line' then
-- do nothing
elseif drawing.pending.mode == 'polygon' or drawing.pending.mode == 'rectangle' or drawing.pending.mode == 'square' then
drawing.pending.p1 = drawing.pending.vertices[1]
elseif drawing.pending.mode == 'circle' or drawing.pending.mode == 'arc' then