diff --git a/editor/graphite-test-document.graphite b/editor/graphite-test-document.graphite index 04888de7..59bad99e 100644 --- a/editor/graphite-test-document.graphite +++ b/editor/graphite-test-document.graphite @@ -1 +1 @@ -{"graphene_document":{"root":{"visible":true,"name":null,"data":{"Folder":{"next_assignment_id":5985789465543063412,"layer_ids":[3526279254690554630,14455049941182576981,2264120728080545131,11029257369377086983,11600227885950905622,5985789465543063411],"layers":[{"visible":true,"name":null,"data":{"Shape":{"shape":{"elements":[{"points":[{"position":[0.5,1.0],"manipulator_type":"Anchor"},{"position":[0.7761415,1.0],"manipulator_type":"InHandle"},{"position":[0.22385850000000002,1.0],"manipulator_type":"OutHandle"}]},{"points":[{"position":[0.0,0.5],"manipulator_type":"Anchor"},{"position":[0.0,0.7761415],"manipulator_type":"InHandle"},{"position":[0.0,0.22385850000000002],"manipulator_type":"OutHandle"}]},{"points":[{"position":[0.5,0.0],"manipulator_type":"Anchor"},{"position":[0.22385850000000002,0.0],"manipulator_type":"InHandle"},{"position":[0.7761415,0.0],"manipulator_type":"OutHandle"}]},{"points":[{"position":[1.0,0.5],"manipulator_type":"Anchor"},{"position":[1.0,0.22385850000000002],"manipulator_type":"InHandle"},{"position":[1.0,0.7761415],"manipulator_type":"OutHandle"}]},{"points":[null,null,null]}],"element_ids":[1,2,3,4,5]},"style":{"stroke":null,"fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"render_index":1}},"transform":{"matrix2":[369.0,0.0,-0.0,480.0],"translation":[-927.566650390625,-365.5]},"blend_mode":"Normal","opacity":1.0},{"visible":true,"name":null,"data":{"Shape":{"shape":{"elements":[{"points":[{"position":[-865.566650390625,-424.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-864.566650390625,-424.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-854.566650390625,-427.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-832.566650390625,-429.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-793.566650390625,-433.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-743.566650390625,-435.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-682.566650390625,-435.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-615.566650390625,-437.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-560.566650390625,-439.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-509.566650390625,-435.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-480.566650390625,-429.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-453.566650390625,-417.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-419.566650390625,-398.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-379.566650390625,-376.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-356.566650390625,-359.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-335.566650390625,-339.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-325.566650390625,-319.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-312.566650390625,-288.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-304.566650390625,-257.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-299.566650390625,-225.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-298.566650390625,-205.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-298.566650390625,-182.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-298.566650390625,-163.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-299.566650390625,-141.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-304.566650390625,-113.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-308.566650390625,-87.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-311.566650390625,-67.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-314.566650390625,-48.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-316.566650390625,-35.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-322.566650390625,-17.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-326.566650390625,-5.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-334.566650390625,14.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-338.566650390625,27.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-345.566650390625,45.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-348.566650390625,55.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-354.566650390625,70.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-360.566650390625,83.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-365.566650390625,91.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-369.566650390625,98.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-375.566650390625,106.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-381.566650390625,114.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-385.566650390625,122.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-394.566650390625,130.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-402.566650390625,137.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-409.566650390625,142.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-417.566650390625,148.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-426.566650390625,154.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-437.566650390625,161.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-451.566650390625,166.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-468.566650390625,175.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-483.566650390625,181.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-507.566650390625,188.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-527.566650390625,193.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-552.566650390625,197.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-576.566650390625,200.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-605.566650390625,201.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-631.566650390625,201.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-661.566650390625,201.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-691.566650390625,200.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-724.566650390625,198.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-751.566650390625,195.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-778.566650390625,191.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-797.566650390625,190.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-832.566650390625,187.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-857.566650390625,183.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-897.566650390625,176.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-925.566650390625,171.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-964.566650390625,160.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-985.566650390625,152.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1010.566650390625,143.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1022.566650390625,137.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1029.566650390625,133.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1036.566650390625,127.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1042.566650390625,117.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1047.566650390625,98.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1051.566650390625,70.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1058.566650390625,37.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1062.566650390625,5.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1069.566650390625,-37.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1076.566650390625,-84.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1076.566650390625,-130.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1071.566650390625,-180.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1069.566650390625,-206.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1069.566650390625,-230.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1069.566650390625,-247.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1066.566650390625,-272.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1065.566650390625,-291.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1062.566650390625,-315.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1059.566650390625,-328.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1058.566650390625,-337.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1055.566650390625,-348.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1049.566650390625,-360.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1041.566650390625,-377.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1033.566650390625,-393.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1024.566650390625,-407.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1020.566650390625,-413.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1015.566650390625,-418.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-1001.566650390625,-430.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-990.566650390625,-436.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-977.566650390625,-441.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-967.566650390625,-444.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-959.566650390625,-444.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-952.566650390625,-444.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-933.566650390625,-442.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-905.566650390625,-436.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-889.566650390625,-432.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-880.566650390625,-430.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-877.566650390625,-429.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-876.566650390625,-428.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-874.566650390625,-426.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-870.566650390625,-424.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-869.566650390625,-424.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-867.566650390625,-424.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-865.566650390625,-424.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-861.566650390625,-425.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-857.566650390625,-426.5],"manipulator_type":"Anchor"},null,null]},{"points":[{"position":[-853.566650390625,-427.5],"manipulator_type":"Anchor"},null,null]}],"element_ids":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117]},"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":5.0,"dash_lengths":[0.0],"dash_offset":0.0,"line_cap":"Butt","line_join":"Miter","line_join_miter_limit":4.0},"fill":"None"},"render_index":0}},"transform":{"matrix2":[1.0,0.0,0.0,1.0],"translation":[0.0,0.0]},"blend_mode":"Normal","opacity":1.0},{"visible":true,"name":null,"data":{"Shape":{"shape":{"elements":[{"points":[{"position":[0.5,1.0],"manipulator_type":"Anchor"},{"position":[0.7761415,1.0],"manipulator_type":"InHandle"},{"position":[0.22385850000000002,1.0],"manipulator_type":"OutHandle"}]},{"points":[{"position":[0.0,0.5],"manipulator_type":"Anchor"},{"position":[0.0,0.7761415],"manipulator_type":"InHandle"},{"position":[0.0,0.22385850000000002],"manipulator_type":"OutHandle"}]},{"points":[{"position":[0.5,0.0],"manipulator_type":"Anchor"},{"position":[0.22385850000000002,0.0],"manipulator_type":"InHandle"},{"position":[0.7761415,0.0],"manipulator_type":"OutHandle"}]},{"points":[{"position":[1.0,0.5],"manipulator_type":"Anchor"},{"position":[1.0,0.22385850000000002],"manipulator_type":"InHandle"},{"position":[1.0,0.7761415],"manipulator_type":"OutHandle"}]},{"points":[null,null,null]}],"element_ids":[1,2,3,4,5]},"style":{"stroke":null,"fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"render_index":1}},"transform":{"matrix2":[337.94872665058745,-35.51369323805279,47.56585157675848,452.6372085455832],"translation":[92.9195736497411,-415.17298085605853]},"blend_mode":"Normal","opacity":1.0},{"visible":true,"name":null,"data":{"Shape":{"shape":{"elements":[{"points":[{"position":[-48.69253069314482,-159.10513506221514],"manipulator_type":"Anchor"},null,{"position":[-70.52138079035899,-513.9526137439627],"manipulator_type":"OutHandle"}]},{"points":[{"position":[222.83237058696454,-503.0361992753027],"manipulator_type":"Anchor"},{"position":[-158.90270804291185,-442.8223058399684],"manipulator_type":"InHandle"},{"position":[604.5674492168409,-563.250092710637],"manipulator_type":"OutHandle"}]},{"points":[{"position":[664.0813704731281,-320.5874513553998],"manipulator_type":"Anchor"},{"position":[669.902428975468,-471.1676241628193],"manipulator_type":"InHandle"},{"position":[658.2603119707883,-170.00727854798032],"manipulator_type":"OutHandle"}]},{"points":[{"position":[561.9483011516083,149.32709051135873],"manipulator_type":"Anchor"},{"position":[779.4132177618326,129.56669690727574],"manipulator_type":"InHandle"},{"position":[344.4833845413841,169.08748411544173],"manipulator_type":"OutHandle"}]},{"points":[{"position":[-68.1412419353403,141.32950801660445],"manipulator_type":"Anchor"},{"position":[-11.996778942496576,322.5035681388116],"manipulator_type":"InHandle"},{"position":[-98.31104242698265,43.97377680505987],"manipulator_type":"OutHandle"}]},{"points":[{"position":[-49.90031956271264,-155.88608010049916],"manipulator_type":"Anchor"},{"position":[-49.90031956271264,-155.88608010049916],"manipulator_type":"InHandle"},{"position":[-49.90031956271264,-155.88608010049916],"manipulator_type":"OutHandle"}]}],"element_ids":[1,2,3,4,5,6]},"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":5.0,"dash_lengths":[0.0],"dash_offset":0.0,"line_cap":"Butt","line_join":"Miter","line_join_miter_limit":4.0},"fill":"None"},"render_index":1}},"transform":{"matrix2":[1.0,0.0,0.0,1.0],"translation":[0.0,0.0]},"blend_mode":"Normal","opacity":1.0},{"visible":true,"name":null,"data":{"Shape":{"shape":{"elements":[{"points":[{"position":[-851.5216124852599,440.1011734805685],"manipulator_type":"Anchor"},null,{"position":[-745.4998088356991,742.8112831395855],"manipulator_type":"OutHandle"}]},{"points":[{"position":[90.98724947544201,508.0318434771365],"manipulator_type":"Anchor"},{"position":[-127.65914203173338,840.2218480977616],"manipulator_type":"InHandle"},{"position":[90.98724947544201,508.0318434771365],"manipulator_type":"OutHandle"}]}],"element_ids":[1,2]},"style":{"stroke":{"color":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0},"weight":5.0,"dash_lengths":[0.0],"dash_offset":0.0,"line_cap":"Butt","line_join":"Miter","line_join_miter_limit":4.0},"fill":"None"},"render_index":1}},"transform":{"matrix2":[1.0,0.0,0.0,1.0],"translation":[0.0,0.0]},"blend_mode":"Normal","opacity":1.0},{"visible":true,"name":null,"data":{"Text":{"text":"ein Fisch","path_style":{"stroke":null,"fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"size":24.0,"line_width":null,"font":{"font_family":"Metal Mania","font_style":"Normal (400)"}}},"transform":{"matrix2":[17.266988107524366,-1.8145193943273525,1.814519394327352,17.266988107524366],"translation":[-884.6986699020281,-831.9173312579314]},"blend_mode":"Normal","opacity":1.0}]}},"transform":{"matrix2":[0.42065729978864125,0.0442052096218941,-0.0442052096218941,0.42065729978864125],"translation":[991.1799052249601,406.7405332186784]},"blend_mode":"Normal","opacity":1.0}},"saved_document_identifier":1812026093844533227,"name":"Untitled Document","version":"0.0.11","document_mode":"DesignMode","view_mode":"Normal","snapping_enabled":true,"overlays_visible":true,"layer_metadata":[[[3526279254690554630],{"selected":false,"expanded":false}],[[14455049941182576981],{"selected":false,"expanded":false}],[[2264120728080545131],{"selected":false,"expanded":false}],[[],{"selected":false,"expanded":true}],[[11600227885950905622],{"selected":false,"expanded":false}],[[5985789465543063411],{"selected":false,"expanded":false}],[[11029257369377086983],{"selected":false,"expanded":false}]],"layer_range_selection_reference":[],"navigation_handler":{"pan":[172.02008130552463,39.54846254599968],"panning":false,"snap_tilt":false,"snap_tilt_released":false,"tilt":0.10470175813131441,"tilting":false,"zoom":0.4229735977849993,"zooming":false,"snap_zoom":false,"mouse_position":[1485.0,319.0]},"artboard_message_handler":{"artboards_graphene_document":{"root":{"visible":true,"name":null,"data":{"Folder":{"next_assignment_id":0,"layer_ids":[],"layers":[]}},"transform":{"matrix2":[0.42065729978864125,0.0442052096218941,-0.0442052096218941,0.42065729978864125],"translation":[991.1799052249601,406.7405332186784]},"blend_mode":"Normal","opacity":1.0}},"artboard_ids":[]},"properties_panel_message_handler":{"active_selection":null}} +{"graphene_document":{"root":{"visible":true,"name":null,"data":{"Folder":{"next_assignment_id":10689566813179949075,"layer_ids":[10689566813179949074],"layers":[{"visible":true,"name":"Folder 1","data":{"Folder":{"next_assignment_id":17222868332373661780,"layer_ids":[17222868332373661779],"layers":[{"visible":true,"name":"Shape 1","data":{"Shape":{"shape":{"elements":[{"points":[{"position":[0.5,1.0],"manipulator_type":"Anchor"},{"position":[0.7761415,1.0],"manipulator_type":"InHandle"},{"position":[0.22385850000000002,1.0],"manipulator_type":"OutHandle"}]},{"points":[{"position":[0.0,0.5],"manipulator_type":"Anchor"},{"position":[0.0,0.7761415],"manipulator_type":"InHandle"},{"position":[0.0,0.22385850000000002],"manipulator_type":"OutHandle"}]},{"points":[{"position":[0.5,0.0],"manipulator_type":"Anchor"},{"position":[0.22385850000000002,0.0],"manipulator_type":"InHandle"},{"position":[0.7761415,0.0],"manipulator_type":"OutHandle"}]},{"points":[{"position":[1.0,0.5],"manipulator_type":"Anchor"},{"position":[1.0,0.22385850000000002],"manipulator_type":"InHandle"},{"position":[1.0,0.7761415],"manipulator_type":"OutHandle"}]},{"points":[null,null,null]}],"element_ids":[1,2,3,4,5]},"style":{"stroke":null,"fill":{"Solid":{"red":0.0,"green":0.0,"blue":0.0,"alpha":1.0}}},"render_index":1}},"transform":{"matrix2":[379.0,0.0,-0.0,239.0],"translation":[-479.3046875,-99.5]},"blend_mode":"Normal","opacity":1.0}]}},"transform":{"matrix2":[1.0,0.0,0.0,1.0],"translation":[0.0,0.0]},"blend_mode":"Normal","opacity":1.0}]}},"transform":{"matrix2":[1.0,0.0,0.0,1.0],"translation":[1060.3046875,373.5]},"blend_mode":"Normal","opacity":1.0}},"saved_document_identifier":6520881531418194372,"name":"Untitled Document","version":"0.0.12","document_mode":"DesignMode","view_mode":"Normal","snapping_enabled":true,"overlays_visible":true,"layer_metadata":[[[],{"selected":false,"expanded":true}],[[10689566813179949074],{"selected":false,"expanded":true}],[[10689566813179949074,17222868332373661779],{"selected":true,"expanded":false}]],"layer_range_selection_reference":[10689566813179949074,17222868332373661779],"navigation_handler":{"pan":[0.0,0.0],"panning":false,"snap_tilt":false,"snap_tilt_released":false,"tilt":0.0,"tilting":false,"zoom":1.0,"zooming":false,"snap_zoom":false,"mouse_position":[0.0,0.0]},"artboard_message_handler":{"artboards_graphene_document":{"root":{"visible":true,"name":null,"data":{"Folder":{"next_assignment_id":0,"layer_ids":[],"layers":[]}},"transform":{"matrix2":[1.0,0.0,0.0,1.0],"translation":[1060.3046875,373.5]},"blend_mode":"Normal","opacity":1.0}},"artboard_ids":[]},"properties_panel_message_handler":{"active_selection":[[10689566813179949074,17222868332373661779],"Artwork"]}} \ No newline at end of file diff --git a/editor/src/consts.rs b/editor/src/consts.rs index 2ce4c2d4..a12e23dd 100644 --- a/editor/src/consts.rs +++ b/editor/src/consts.rs @@ -63,9 +63,6 @@ pub const SCROLLBAR_SPACING: f64 = 0.1; pub const ASYMPTOTIC_EFFECT: f64 = 0.5; pub const SCALE_EFFECT: f64 = 0.5; -pub const DEFAULT_DOCUMENT_NAME: &str = "Untitled Document"; -pub const FILE_SAVE_SUFFIX: &str = ".graphite"; - // Colors pub const COLOR_ACCENT: Color = Color::from_unsafe(0x00 as f32 / 255., 0xA8 as f32 / 255., 0xFF as f32 / 255.); @@ -74,5 +71,8 @@ pub const DEFAULT_FONT_FAMILY: &str = "Merriweather"; pub const DEFAULT_FONT_STYLE: &str = "Normal (400)"; // Document -pub const GRAPHITE_DOCUMENT_VERSION: &str = "0.0.11"; // Remember to save a simple document and replace the test file `graphite-test-document.graphite` +pub const GRAPHITE_DOCUMENT_VERSION: &str = "0.0.12"; // Remember to save a simple document and replace the test file `graphite-test-document.graphite` +pub const DEFAULT_DOCUMENT_NAME: &str = "Untitled Document"; +pub const FILE_SAVE_SUFFIX: &str = ".graphite"; + pub const VIEWPORT_ZOOM_TO_FIT_PADDING_SCALE_FACTOR: f32 = 1.05; diff --git a/editor/src/messages/frontend/frontend_message.rs b/editor/src/messages/frontend/frontend_message.rs index 8071cf34..12f8ff9a 100644 --- a/editor/src/messages/frontend/frontend_message.rs +++ b/editor/src/messages/frontend/frontend_message.rs @@ -16,50 +16,166 @@ use serde::{Deserialize, Serialize}; #[derive(PartialEq, Clone, Debug, Serialize, Deserialize)] pub enum FrontendMessage { // Display prefix: make the frontend show something, like a dialog - DisplayDialog { icon: String }, + DisplayDialog { + icon: String, + }, DisplayDialogDismiss, - DisplayDialogPanic { panic_info: String, header: String, description: String }, - DisplayEditableTextbox { text: String, line_width: Option, font_size: f64, color: Color }, + DisplayDialogPanic { + #[serde(rename = "panicInfo")] + panic_info: String, + header: String, + description: String, + }, + DisplayEditableTextbox { + text: String, + #[serde(rename = "lineWidth")] + line_width: Option, + #[serde(rename = "fontSize")] + font_size: f64, + color: Color, + }, DisplayRemoveEditableTextbox, // Trigger prefix: cause a browser API to do something - TriggerAboutGraphiteLocalizedCommitDate { commit_date: String }, - TriggerFileDownload { document: String, name: String }, - TriggerFontLoad { font: Font, is_default: bool }, + TriggerAboutGraphiteLocalizedCommitDate { + #[serde(rename = "commitDate")] + commit_date: String, + }, + TriggerFileDownload { + document: String, + name: String, + }, + TriggerFontLoad { + font: Font, + #[serde(rename = "isDefault")] + is_default: bool, + }, TriggerImport, - TriggerIndexedDbRemoveDocument { document_id: u64 }, - TriggerIndexedDbWriteDocument { document: String, details: FrontendDocumentDetails, version: String }, + TriggerIndexedDbRemoveDocument { + #[serde(rename = "documentId")] + document_id: u64, + }, + TriggerIndexedDbWriteDocument { + document: String, + details: FrontendDocumentDetails, + version: String, + }, TriggerOpenDocument, TriggerPaste, - TriggerRasterDownload { document: String, name: String, mime: String, size: (f64, f64) }, + TriggerRasterDownload { + document: String, + name: String, + mime: String, + size: (f64, f64), + }, TriggerRefreshBoundsOfViewports, TriggerTextCommit, - TriggerTextCopy { copy_text: String }, + TriggerTextCopy { + #[serde(rename = "copyText")] + copy_text: String, + }, TriggerViewportResize, - TriggerVisitLink { url: String }, + TriggerVisitLink { + url: String, + }, // Update prefix: give the frontend a new value or state for it to use - UpdateActiveDocument { document_id: u64 }, - UpdateDialogDetails { layout_target: LayoutTarget, layout: SubLayout }, - UpdateDocumentArtboards { svg: String }, - UpdateDocumentArtwork { svg: String }, - UpdateDocumentBarLayout { layout_target: LayoutTarget, layout: SubLayout }, - UpdateDocumentLayerDetails { data: LayerPanelEntry }, - UpdateDocumentLayerTreeStructure { data_buffer: RawBuffer }, - UpdateDocumentModeLayout { layout_target: LayoutTarget, layout: SubLayout }, - UpdateDocumentOverlays { svg: String }, - UpdateDocumentRulers { origin: (f64, f64), spacing: f64, interval: f64 }, - UpdateDocumentScrollbars { position: (f64, f64), size: (f64, f64), multiplier: (f64, f64) }, - UpdateImageData { image_data: Vec }, - UpdateInputHints { hint_data: HintData }, - UpdateLayerTreeOptionsLayout { layout_target: LayoutTarget, layout: SubLayout }, - UpdateMenuBarLayout { layout_target: LayoutTarget, layout: Vec }, - UpdateMouseCursor { cursor: MouseCursorIcon }, - UpdateNodeGraphVisibility { visible: bool }, - UpdateOpenDocumentsList { open_documents: Vec }, - UpdatePropertyPanelOptionsLayout { layout_target: LayoutTarget, layout: SubLayout }, - UpdatePropertyPanelSectionsLayout { layout_target: LayoutTarget, layout: SubLayout }, - UpdateToolOptionsLayout { layout_target: LayoutTarget, layout: SubLayout }, - UpdateToolShelfLayout { layout_target: LayoutTarget, layout: SubLayout }, - UpdateWorkingColorsLayout { layout_target: LayoutTarget, layout: SubLayout }, + UpdateActiveDocument { + #[serde(rename = "documentId")] + document_id: u64, + }, + UpdateDialogDetails { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + layout: SubLayout, + }, + UpdateDocumentArtboards { + svg: String, + }, + UpdateDocumentArtwork { + svg: String, + }, + UpdateDocumentBarLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + layout: SubLayout, + }, + UpdateDocumentLayerDetails { + data: LayerPanelEntry, + }, + UpdateDocumentLayerTreeStructure { + #[serde(rename = "dataBuffer")] + data_buffer: RawBuffer, + }, + UpdateDocumentModeLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + layout: SubLayout, + }, + UpdateDocumentOverlays { + svg: String, + }, + UpdateDocumentRulers { + origin: (f64, f64), + spacing: f64, + interval: f64, + }, + UpdateDocumentScrollbars { + position: (f64, f64), + size: (f64, f64), + multiplier: (f64, f64), + }, + UpdateImageData { + #[serde(rename = "imageData")] + image_data: Vec, + }, + UpdateInputHints { + #[serde(rename = "hintData")] + hint_data: HintData, + }, + UpdateLayerTreeOptionsLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + layout: SubLayout, + }, + UpdateMenuBarLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + layout: Vec, + }, + UpdateMouseCursor { + cursor: MouseCursorIcon, + }, + UpdateNodeGraphVisibility { + visible: bool, + }, + UpdateOpenDocumentsList { + #[serde(rename = "openDocuments")] + open_documents: Vec, + }, + UpdatePropertyPanelOptionsLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + layout: SubLayout, + }, + UpdatePropertyPanelSectionsLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + layout: SubLayout, + }, + UpdateToolOptionsLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + layout: SubLayout, + }, + UpdateToolShelfLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + layout: SubLayout, + }, + UpdateWorkingColorsLayout { + #[serde(rename = "layoutTarget")] + layout_target: LayoutTarget, + layout: SubLayout, + }, } diff --git a/editor/src/messages/frontend/utility_types.rs b/editor/src/messages/frontend/utility_types.rs index 1a576a14..aa5e53fa 100644 --- a/editor/src/messages/frontend/utility_types.rs +++ b/editor/src/messages/frontend/utility_types.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; #[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)] pub struct FrontendDocumentDetails { + #[serde(rename = "isSaved")] pub is_saved: bool, pub name: String, pub id: u64, diff --git a/editor/src/messages/portfolio/document/utility_types/layer_panel.rs b/editor/src/messages/portfolio/document/utility_types/layer_panel.rs index 47ec02ff..05f2d4f3 100644 --- a/editor/src/messages/portfolio/document/utility_types/layer_panel.rs +++ b/editor/src/messages/portfolio/document/utility_types/layer_panel.rs @@ -48,7 +48,9 @@ impl LayerMetadata { pub struct LayerPanelEntry { pub name: String, pub visible: bool, + #[serde(rename = "layerType")] pub layer_type: LayerDataTypeDiscriminant, + #[serde(rename = "layerMetadata")] pub layer_metadata: LayerMetadata, pub path: Vec, pub thumbnail: String, diff --git a/frontend/src/App.vue b/frontend/src/App.vue index def44c42..c2f5316e 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -295,7 +295,7 @@ export default defineComponent({ // Initialize certain setup tasks required by the editor backend to be ready for the user now that the frontend is ready const platform = operatingSystem(); - this.editor.instance.init_after_frontend_ready(platform); + this.editor.instance.initAfterFrontendReady(platform); }, beforeUnmount() { // Call the destructor for each manager diff --git a/frontend/src/components/panels/Document.vue b/frontend/src/components/panels/Document.vue index 63a6c1ac..80a102a1 100644 --- a/frontend/src/components/panels/Document.vue +++ b/frontend/src/components/panels/Document.vue @@ -256,27 +256,27 @@ export default defineComponent({ const buffer = await file.arrayBuffer(); const u8Array = new Uint8Array(buffer); - this.editor.instance.paste_image(file.type, u8Array, e.clientX, e.clientY); + this.editor.instance.pasteImage(file.type, u8Array, e.clientX, e.clientY); } }); }, translateCanvasX(newValue: number) { const delta = newValue - this.scrollbarPos.x; this.scrollbarPos.x = newValue; - this.editor.instance.translate_canvas(-delta * this.scrollbarMultiplier.x, 0); + this.editor.instance.translateCanvas(-delta * this.scrollbarMultiplier.x, 0); }, translateCanvasY(newValue: number) { const delta = newValue - this.scrollbarPos.y; this.scrollbarPos.y = newValue; - this.editor.instance.translate_canvas(0, -delta * this.scrollbarMultiplier.y); + this.editor.instance.translateCanvas(0, -delta * this.scrollbarMultiplier.y); }, pageX(delta: number) { const move = delta < 0 ? 1 : -1; - this.editor.instance.translate_canvas_by_fraction(move, 0); + this.editor.instance.translateCanvasByFraction(move, 0); }, pageY(delta: number) { const move = delta < 0 ? 1 : -1; - this.editor.instance.translate_canvas_by_fraction(0, move); + this.editor.instance.translateCanvasByFraction(0, move); }, canvasPointerDown(e: PointerEvent) { const onEditbox = e.target instanceof HTMLDivElement && e.target.contentEditable; @@ -341,7 +341,7 @@ export default defineComponent({ triggerTextCommit() { if (!this.textInput) return; const textCleaned = textInputCleanup(this.textInput.innerText); - this.editor.instance.on_change_text(textCleaned); + this.editor.instance.onChangeText(textCleaned); }, displayEditableTextbox(displayEditableTextbox: DisplayEditableTextbox) { this.textInput = document.createElement("DIV") as HTMLDivElement; @@ -350,14 +350,14 @@ export default defineComponent({ else this.textInput.textContent = `${displayEditableTextbox.text}\n`; this.textInput.contentEditable = "true"; - this.textInput.style.width = displayEditableTextbox.line_width ? `${displayEditableTextbox.line_width}px` : "max-content"; + this.textInput.style.width = displayEditableTextbox.lineWidth ? `${displayEditableTextbox.lineWidth}px` : "max-content"; this.textInput.style.height = "auto"; - this.textInput.style.fontSize = `${displayEditableTextbox.font_size}px`; + this.textInput.style.fontSize = `${displayEditableTextbox.fontSize}px`; this.textInput.style.color = displayEditableTextbox.color.toRgbaCSS(); this.textInput.oninput = (): void => { if (!this.textInput) return; - this.editor.instance.update_bounds(textInputCleanup(this.textInput.innerText)); + this.editor.instance.updateBounds(textInputCleanup(this.textInput.innerText)); }; }, displayRemoveEditableTextbox() { diff --git a/frontend/src/components/panels/LayerTree.vue b/frontend/src/components/panels/LayerTree.vue index b8edb3d2..21cfe464 100644 --- a/frontend/src/components/panels/LayerTree.vue +++ b/frontend/src/components/panels/LayerTree.vue @@ -23,16 +23,16 @@
- - - - + + + + , // TODO: replace with BigUint64Array as index layers: [] as LayerListingInfo[], - devMode: process.env.NODE_ENV === "development", // Interactive dragging draggable: true, @@ -313,10 +312,10 @@ export default defineComponent({ return `${height}px`; }, toggleLayerVisibility(path: BigUint64Array) { - this.editor.instance.toggle_layer_visibility(path); + this.editor.instance.toggleLayerVisibility(path); }, handleExpandArrowClick(path: BigUint64Array) { - this.editor.instance.toggle_layer_expansion(path); + this.editor.instance.toggleLayerExpansion(path); }, async onEditLayerName(listing: LayerListingInfo) { if (listing.editingName) return; @@ -337,7 +336,7 @@ export default defineComponent({ const name = (inputElement as HTMLInputElement).value; listing.editingName = false; - this.editor.instance.set_layer_name(listing.entry.path, name); + this.editor.instance.setLayerName(listing.entry.path, name); }, async onEditLayerNameDeselect(listing: LayerListingInfo) { this.draggable = true; @@ -354,14 +353,14 @@ export default defineComponent({ // Pressing the Ctrl key on a Mac, or the Cmd key on another platform, is a violation of the `.exact` qualifier so we filter it out here const opposite = platformIsMac() ? ctrl : cmd; - if (!opposite) this.editor.instance.select_layer(listing.entry.path, ctrlOrCmd, shift); + if (!opposite) this.editor.instance.selectLayer(listing.entry.path, ctrlOrCmd, shift); // We always want to stop propagation so the click event doesn't pass through the layer and cause a deselection by clicking the layer panel background // This is also why we cover the remaining cases not considered by the `.exact` qualifier, in the last two bindings on the layer element, with a `stopPropagation()` call event.stopPropagation(); }, async deselectAllLayers() { - this.editor.instance.deselect_all_layers(); + this.editor.instance.deselectAllLayers(); }, calculateDragIndex(tree: HTMLElement, clientY: number): DraggingData { const treeChildren = tree.children; @@ -405,9 +404,9 @@ export default defineComponent({ } // Inserting below current row else if (distance > -closest && distance > -RANGE_TO_INSERT_WITHIN_BOTTOM_FOLDER_NOT_ROOT && distance < 0) { - insertFolder = layer.layer_type === "Folder" ? layer.path : layer.path.slice(0, layer.path.length - 1); - insertIndex = layer.layer_type === "Folder" ? 0 : folderIndex + 1; - highlightFolder = layer.layer_type === "Folder"; + insertFolder = layer.layerType === "Folder" ? layer.path : layer.path.slice(0, layer.path.length - 1); + insertIndex = layer.layerType === "Folder" ? 0 : folderIndex + 1; + highlightFolder = layer.layerType === "Folder"; closest = -distance; markerHeight = index === treeChildren.length - 1 ? rect.bottom - INSERT_MARK_OFFSET : rect.bottom; } @@ -426,7 +425,7 @@ export default defineComponent({ }, async dragStart(event: DragEvent, listing: LayerListingInfo) { const layer = listing.entry; - if (!layer.layer_metadata.selected) this.selectLayer(event.ctrlKey, event.metaKey, event.shiftKey, listing, event); + if (!layer.layerMetadata.selected) this.selectLayer(event.ctrlKey, event.metaKey, event.shiftKey, listing, event); // Set style of cursor for drag if (event.dataTransfer) { @@ -448,7 +447,7 @@ export default defineComponent({ if (this.draggingData) { const { insertFolder, insertIndex } = this.draggingData; - this.editor.instance.move_layer_in_tree(insertFolder, insertIndex); + this.editor.instance.moveLayerInTree(insertFolder, insertIndex); this.draggingData = undefined; } diff --git a/frontend/src/components/widgets/WidgetLayout.vue b/frontend/src/components/widgets/WidgetLayout.vue index 1e03dc18..5719e189 100644 --- a/frontend/src/components/widgets/WidgetLayout.vue +++ b/frontend/src/components/widgets/WidgetLayout.vue @@ -2,7 +2,7 @@ diff --git a/frontend/src/components/widgets/WidgetRow.vue b/frontend/src/components/widgets/WidgetRow.vue index 9af7d19c..b82a5aff 100644 --- a/frontend/src/components/widgets/WidgetRow.vue +++ b/frontend/src/components/widgets/WidgetRow.vue @@ -122,7 +122,7 @@ export default defineComponent({ }, methods: { updateLayout(widgetId: bigint, value: unknown) { - this.editor.instance.update_layout(this.layoutTarget, widgetId, value); + this.editor.instance.updateLayout(this.layoutTarget, widgetId, value); }, withoutValue(props: Record): Record { const { value: _, ...rest } = props; diff --git a/frontend/src/components/widgets/groups/WidgetSection.vue b/frontend/src/components/widgets/groups/WidgetSection.vue index 96e4aeb6..61a2fe03 100644 --- a/frontend/src/components/widgets/groups/WidgetSection.vue +++ b/frontend/src/components/widgets/groups/WidgetSection.vue @@ -94,7 +94,7 @@ const WidgetSection = defineComponent({ }), methods: { updateLayout(widgetId: bigint, value: unknown) { - this.editor.instance.update_layout(this.layoutTarget, widgetId, value); + this.editor.instance.updateLayout(this.layoutTarget, widgetId, value); }, layoutGroupType(layoutGroup: LayoutGroup): unknown { if (isWidgetRow(layoutGroup)) return WidgetRow; diff --git a/frontend/src/components/widgets/inputs/MenuBarInput.vue b/frontend/src/components/widgets/inputs/MenuBarInput.vue index fb60861f..060fffa0 100644 --- a/frontend/src/components/widgets/inputs/MenuBarInput.vue +++ b/frontend/src/components/widgets/inputs/MenuBarInput.vue @@ -24,7 +24,7 @@ :direction="'Bottom'" :minWidth="240" :drawIcon="true" - :defaultAction="() => editor.instance.request_coming_soon_dialog()" + :defaultAction="() => editor.instance.requestComingSoonDialog()" :ref="(ref: typeof MenuList) => ref && (entry.ref = ref)" /> @@ -111,7 +111,7 @@ export default defineComponent({ group.map((entry) => ({ ...entry, children: entry.children ? menuEntryToFrontendMenuEntry(entry.children) : undefined, - action: (): void => this.editor.instance.update_layout(updateMenuBarLayout.layout_target, entry.action.widgetId, undefined), + action: (): void => this.editor.instance.updateLayout(updateMenuBarLayout.layoutTarget, entry.action.widgetId, undefined), shortcutRequiresLock: entry.shortcut ? shortcutRequiresLock(entry.shortcut.keys) : undefined, })) ); diff --git a/frontend/src/components/widgets/inputs/SwatchPairInput.vue b/frontend/src/components/widgets/inputs/SwatchPairInput.vue index eda3c0a4..2895defd 100644 --- a/frontend/src/components/widgets/inputs/SwatchPairInput.vue +++ b/frontend/src/components/widgets/inputs/SwatchPairInput.vue @@ -105,11 +105,11 @@ export default defineComponent({ }, primaryColorChanged(color: RGBA) { const newColor = rgbaToDecimalRgba(color); - this.editor.instance.update_primary_color(newColor.r, newColor.g, newColor.b, newColor.a); + this.editor.instance.updatePrimaryColor(newColor.r, newColor.g, newColor.b, newColor.a); }, secondaryColorChanged(color: RGBA) { const newColor = rgbaToDecimalRgba(color); - this.editor.instance.update_secondary_color(newColor.r, newColor.g, newColor.b, newColor.a); + this.editor.instance.updateSecondaryColor(newColor.r, newColor.g, newColor.b, newColor.a); }, }, }); diff --git a/frontend/src/components/window/status-bar/StatusBar.vue b/frontend/src/components/window/status-bar/StatusBar.vue index 9f41fbe0..e2fc8fe0 100644 --- a/frontend/src/components/window/status-bar/StatusBar.vue +++ b/frontend/src/components/window/status-bar/StatusBar.vue @@ -70,7 +70,7 @@ export default defineComponent({ }, mounted() { this.editor.subscriptions.subscribeJsMessage(UpdateInputHints, (updateInputHints) => { - this.hintData = updateInputHints.hint_data; + this.hintData = updateInputHints.hintData; }); }, components: { diff --git a/frontend/src/components/window/workspace/Panel.vue b/frontend/src/components/window/workspace/Panel.vue index fbb55b0a..bbbeaf9a 100644 --- a/frontend/src/components/window/workspace/Panel.vue +++ b/frontend/src/components/window/workspace/Panel.vue @@ -252,10 +252,10 @@ export default defineComponent({ }, methods: { newDocument() { - this.editor.instance.new_document_dialog(); + this.editor.instance.newDocumentDialog(); }, openDocument() { - this.editor.instance.document_open(); + this.editor.instance.documentOpen(); }, platformModifiers(reservedKey: boolean): KeysGroup { // TODO: Remove this by properly feeding these keys from a layout provided by the backend diff --git a/frontend/src/components/window/workspace/Workspace.vue b/frontend/src/components/window/workspace/Workspace.vue index 8b8da7b0..ce3a1945 100644 --- a/frontend/src/components/window/workspace/Workspace.vue +++ b/frontend/src/components/window/workspace/Workspace.vue @@ -8,8 +8,8 @@ :tabCloseButtons="true" :tabMinWidths="true" :tabLabels="portfolio.state.documents.map((doc) => doc.displayName)" - :clickAction="(tabIndex) => editor.instance.select_document(portfolio.state.documents[tabIndex].id)" - :closeAction="(tabIndex) => editor.instance.close_document_with_confirmation(portfolio.state.documents[tabIndex].id)" + :clickAction="(tabIndex) => editor.instance.selectDocument(portfolio.state.documents[tabIndex].id)" + :closeAction="(tabIndex) => editor.instance.closeDocumentWithConfirmation(portfolio.state.documents[tabIndex].id)" :tabActiveIndex="portfolio.state.activeDocumentIndex" ref="documentsPanel" /> diff --git a/frontend/src/io-managers/blob.ts b/frontend/src/io-managers/blob.ts index 2696f120..b8b2d7a2 100644 --- a/frontend/src/io-managers/blob.ts +++ b/frontend/src/io-managers/blob.ts @@ -4,15 +4,15 @@ import { UpdateImageData } from "@/wasm-communication/messages"; export function createBlobManager(editor: Editor): void { // Subscribe to process backend event editor.subscriptions.subscribeJsMessage(UpdateImageData, (updateImageData) => { - updateImageData.image_data.forEach(async (element) => { - // Using updateImageData.image_data.buffer returns undefined for some reason? - const blob = new Blob([new Uint8Array(element.image_data.values()).buffer], { type: element.mime }); + updateImageData.imageData.forEach(async (element) => { + // Using updateImageData.imageData.buffer returns undefined for some reason? + const blob = new Blob([new Uint8Array(element.imageData.values()).buffer], { type: element.mime }); const url = URL.createObjectURL(blob); const image = await createImageBitmap(blob); - editor.instance.set_image_blob_url(element.path, url, image.width, image.height); + editor.instance.setImageBlobUrl(element.path, url, image.width, image.height); }); }); } diff --git a/frontend/src/io-managers/clipboard.ts b/frontend/src/io-managers/clipboard.ts index 6d766598..e9408497 100644 --- a/frontend/src/io-managers/clipboard.ts +++ b/frontend/src/io-managers/clipboard.ts @@ -5,6 +5,6 @@ export function createClipboardManager(editor: Editor): void { // Subscribe to process backend event editor.subscriptions.subscribeJsMessage(TriggerTextCopy, (triggerTextCopy) => { // If the Clipboard API is supported in the browser, copy text to the clipboard - navigator.clipboard?.writeText?.(triggerTextCopy.copy_text); + navigator.clipboard?.writeText?.(triggerTextCopy.copyText); }); } diff --git a/frontend/src/io-managers/input.ts b/frontend/src/io-managers/input.ts index 8bdce906..f494a497 100644 --- a/frontend/src/io-managers/input.ts +++ b/frontend/src/io-managers/input.ts @@ -106,7 +106,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo if (await shouldRedirectKeyboardEventToBackend(e)) { e.preventDefault(); const modifiers = makeKeyboardModifiersBitfield(e); - editor.instance.on_key_down(key, modifiers); + editor.instance.onKeyDown(key, modifiers); return; } @@ -121,7 +121,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo if (await shouldRedirectKeyboardEventToBackend(e)) { e.preventDefault(); const modifiers = makeKeyboardModifiersBitfield(e); - editor.instance.on_key_up(key, modifiers); + editor.instance.onKeyUp(key, modifiers); } } @@ -146,7 +146,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo } const modifiers = makeKeyboardModifiersBitfield(e); - editor.instance.on_mouse_move(e.clientX, e.clientY, e.buttons, modifiers); + editor.instance.onMouseMove(e.clientX, e.clientY, e.buttons, modifiers); } function onPointerDown(e: PointerEvent): void { @@ -162,13 +162,13 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo } if (!inTextInput) { - if (textInput) editor.instance.on_change_text(textInputCleanup(textInput.innerText)); + if (textInput) editor.instance.onChangeText(textInputCleanup(textInput.innerText)); else viewportPointerInteractionOngoing = isTargetingCanvas instanceof Element; } if (viewportPointerInteractionOngoing) { const modifiers = makeKeyboardModifiersBitfield(e); - editor.instance.on_mouse_down(e.clientX, e.clientY, e.buttons, modifiers); + editor.instance.onMouseDown(e.clientX, e.clientY, e.buttons, modifiers); } } @@ -177,7 +177,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo if (!textInput) { const modifiers = makeKeyboardModifiersBitfield(e); - editor.instance.on_mouse_up(e.clientX, e.clientY, e.buttons, modifiers); + editor.instance.onMouseUp(e.clientX, e.clientY, e.buttons, modifiers); } } @@ -186,7 +186,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo if (!textInput) { const modifiers = makeKeyboardModifiersBitfield(e); - editor.instance.on_double_click(e.clientX, e.clientY, e.buttons, modifiers); + editor.instance.onDoubleClick(e.clientX, e.clientY, e.buttons, modifiers); } } @@ -213,7 +213,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo if (isTargetingCanvas) { e.preventDefault(); const modifiers = makeKeyboardModifiersBitfield(e); - editor.instance.on_wheel_scroll(e.clientX, e.clientY, e.buttons, e.deltaX, e.deltaY, e.deltaZ, modifiers); + editor.instance.onWheelScroll(e.clientX, e.clientY, e.buttons, e.deltaX, e.deltaY, e.deltaZ, modifiers); } } @@ -233,20 +233,20 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo const flattened = boundsOfViewports.flat(); const data = Float64Array.from(flattened); - if (boundsOfViewports.length > 0) editor.instance.bounds_of_viewports(data); + if (boundsOfViewports.length > 0) editor.instance.boundsOfViewports(data); } function onBeforeUnload(e: BeforeUnloadEvent): void { const activeDocument = document.state.documents[document.state.activeDocumentIndex]; - if (!activeDocument.is_saved) editor.instance.trigger_auto_save(activeDocument.id); + if (!activeDocument.isSaved) editor.instance.triggerAutoSave(activeDocument.id); // Skip the message if the editor crashed, since work is already lost - if (editor.instance.has_crashed()) return; + if (editor.instance.hasCrashed()) return; // Skip the message during development, since it's annoying when testing if (process.env.NODE_ENV === "development") return; - const allDocumentsSaved = document.state.documents.reduce((acc, doc) => acc && doc.is_saved, true); + const allDocumentsSaved = document.state.documents.reduce((acc, doc) => acc && doc.isSaved, true); if (!allDocumentsSaved) { e.returnValue = "Unsaved work will be lost if the web browser tab is closed. Close anyway?"; e.preventDefault(); @@ -262,7 +262,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo if (item.type === "text/plain") { item.getAsString((text) => { if (text.startsWith("graphite/layer: ")) { - editor.instance.paste_serialized_data(text.substring(16, text.length)); + editor.instance.pasteSerializedData(text.substring(16, text.length)); } }); } @@ -272,7 +272,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo file.arrayBuffer().then((buffer): void => { const u8Array = new Uint8Array(buffer); - editor.instance.paste_image(file.type, u8Array); + editor.instance.pasteImage(file.type, u8Array); }); } }); @@ -305,7 +305,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo const text = reader.result as string; if (text.startsWith("graphite/layer: ")) { - editor.instance.paste_serialized_data(text.substring(16, text.length)); + editor.instance.pasteSerializedData(text.substring(16, text.length)); } }; reader.readAsText(blob); @@ -319,7 +319,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo reader.onload = (): void => { const u8Array = new Uint8Array(reader.result as ArrayBuffer); - editor.instance.paste_image(imageType, u8Array); + editor.instance.pasteImage(imageType, u8Array); }; reader.readAsArrayBuffer(blob); } @@ -343,7 +343,7 @@ export function createInputManager(editor: Editor, container: HTMLElement, dialo }; const message = Object.entries(matchMessage).find(([key]) => String(err).includes(key))?.[1] || String(err); - editor.instance.error_dialog("Cannot access clipboard", message); + editor.instance.errorDialog("Cannot access clipboard", message); } }); diff --git a/frontend/src/io-managers/localization.ts b/frontend/src/io-managers/localization.ts index c58b861e..3c40dc62 100644 --- a/frontend/src/io-managers/localization.ts +++ b/frontend/src/io-managers/localization.ts @@ -19,7 +19,7 @@ export function createLocalizationManager(editor: Editor): void { // Subscribe to process backend event editor.subscriptions.subscribeJsMessage(TriggerAboutGraphiteLocalizedCommitDate, (triggerAboutGraphiteLocalizedCommitDate) => { - const localized = localizeTimestamp(triggerAboutGraphiteLocalizedCommitDate.commit_date); - editor.instance.request_about_graphite_dialog_with_localized_commit_date(localized); + const localized = localizeTimestamp(triggerAboutGraphiteLocalizedCommitDate.commitDate); + editor.instance.requestAboutGraphiteDialogWithLocalizedCommitDate(localized); }); } diff --git a/frontend/src/io-managers/panic.ts b/frontend/src/io-managers/panic.ts index 505a9832..a79cf139 100644 --- a/frontend/src/io-managers/panic.ts +++ b/frontend/src/io-managers/panic.ts @@ -13,7 +13,7 @@ export function createPanicManager(editor: Editor, dialogState: DialogState): vo // eslint-disable-next-line @typescript-eslint/no-explicit-any (Error as any).stackTraceLimit = Infinity; const stackTrace = new Error().stack || ""; - const panicDetails = `${displayDialogPanic.panic_info}${stackTrace ? `\n\n${stackTrace}` : ""}`; + const panicDetails = `${displayDialogPanic.panicInfo}${stackTrace ? `\n\n${stackTrace}` : ""}`; // eslint-disable-next-line no-console console.error(panicDetails); @@ -29,8 +29,7 @@ function preparePanicDialog(header: string, details: string, panicDetails: strin { rowWidgets: [new Widget({ kind: "TextLabel", value: header, bold: true, italic: false, tableAlign: false, multiline: false }, 0n)] }, { rowWidgets: [new Widget({ kind: "TextLabel", value: details, bold: false, italic: false, tableAlign: false, multiline: true }, 1n)] }, ], - // eslint-disable-next-line camelcase - layout_target: null, + layoutTarget: null, }; const reloadButton: TextButtonWidget = { diff --git a/frontend/src/io-managers/persistence.ts b/frontend/src/io-managers/persistence.ts index 454fc0d1..9fe11740 100644 --- a/frontend/src/io-managers/persistence.ts +++ b/frontend/src/io-managers/persistence.ts @@ -36,7 +36,7 @@ export async function createPersistenceManager(editor: Editor, portfolio: Portfo storeDocumentOrder(); }); editor.subscriptions.subscribeJsMessage(TriggerIndexedDbRemoveDocument, async (removeAutoSaveDocument) => { - removeDocument(removeAutoSaveDocument.document_id); + removeDocument(removeAutoSaveDocument.documentId); }); // Open the IndexedDB database connection and save it to this variable, which is a promise that resolves once the connection is open @@ -61,7 +61,7 @@ export async function createPersistenceManager(editor: Editor, portfolio: Portfo Error on opening IndexDB: ${dbOpenRequest.error} `; - editor.instance.error_dialog("Document auto-save doesn't work in this browser", errorText); + editor.instance.errorDialog("Document auto-save doesn't work in this browser", errorText); }; dbOpenRequest.onsuccess = (): void => { @@ -82,10 +82,10 @@ export async function createPersistenceManager(editor: Editor, portfolio: Portfo .map((id) => previouslySavedDocuments.find((autoSave) => autoSave.details.id === id)) .filter((x) => x !== undefined) as TriggerIndexedDbWriteDocument[]; - const currentDocumentVersion = editor.instance.graphite_document_version(); + const currentDocumentVersion = editor.instance.graphiteDocumentVersion(); orderedSavedDocuments.forEach((doc: TriggerIndexedDbWriteDocument) => { if (doc.version === currentDocumentVersion) { - editor.instance.open_auto_saved_document(BigInt(doc.details.id), doc.details.name, doc.details.is_saved, doc.document); + editor.instance.openAutoSavedDocument(BigInt(doc.details.id), doc.details.name, doc.details.isSaved, doc.document); } else { removeDocument(doc.details.id); } diff --git a/frontend/src/state-providers/fonts.ts b/frontend/src/state-providers/fonts.ts index f0ef213b..ea7ae0b6 100644 --- a/frontend/src/state-providers/fonts.ts +++ b/frontend/src/state-providers/fonts.ts @@ -48,12 +48,12 @@ export function createFontsState(editor: Editor) { // Subscribe to process backend events editor.subscriptions.subscribeJsMessage(TriggerFontLoad, async (triggerFontLoad) => { - const url = await getFontFileUrl(triggerFontLoad.font.font_family, triggerFontLoad.font.font_style); + const url = await getFontFileUrl(triggerFontLoad.font.fontFamily, triggerFontLoad.font.fontStyle); if (url) { const response = await (await fetch(url)).arrayBuffer(); - editor.instance.on_font_load(triggerFontLoad.font.font_family, triggerFontLoad.font.font_style, url, new Uint8Array(response), triggerFontLoad.is_default); + editor.instance.onFontLoad(triggerFontLoad.font.fontFamily, triggerFontLoad.font.fontStyle, url, new Uint8Array(response), triggerFontLoad.isDefault); } else { - editor.instance.error_dialog("Failed to load font", `The font ${triggerFontLoad.font.font_family} with style ${triggerFontLoad.font.font_style} does not exist`); + editor.instance.errorDialog("Failed to load font", `The font ${triggerFontLoad.font.fontFamily} with style ${triggerFontLoad.font.fontStyle} does not exist`); } }); diff --git a/frontend/src/state-providers/portfolio.ts b/frontend/src/state-providers/portfolio.ts index 44c13429..aab72318 100644 --- a/frontend/src/state-providers/portfolio.ts +++ b/frontend/src/state-providers/portfolio.ts @@ -15,21 +15,21 @@ export function createPortfolioState(editor: Editor) { // Set up message subscriptions on creation editor.subscriptions.subscribeJsMessage(UpdateOpenDocumentsList, (updateOpenDocumentList) => { - state.documents = updateOpenDocumentList.open_documents; + state.documents = updateOpenDocumentList.openDocuments; }); editor.subscriptions.subscribeJsMessage(UpdateActiveDocument, (updateActiveDocument) => { // Assume we receive a correct document id - const activeId = state.documents.findIndex((doc) => doc.id === updateActiveDocument.document_id); + const activeId = state.documents.findIndex((doc) => doc.id === updateActiveDocument.documentId); state.activeDocumentIndex = activeId; }); editor.subscriptions.subscribeJsMessage(TriggerOpenDocument, async () => { - const extension = editor.instance.file_save_suffix(); + const extension = editor.instance.fileSaveSuffix(); const data = await upload(extension, "text"); - editor.instance.open_document_file(data.filename, data.content); + editor.instance.openDocumentFile(data.filename, data.content); }); editor.subscriptions.subscribeJsMessage(TriggerImport, async () => { const data = await upload("image/*", "data"); - editor.instance.paste_image(data.type, Uint8Array.from(data.content)); + editor.instance.pasteImage(data.type, Uint8Array.from(data.content)); }); editor.subscriptions.subscribeJsMessage(TriggerFileDownload, (triggerFileDownload) => { download(triggerFileDownload.name, triggerFileDownload.document); diff --git a/frontend/src/wasm-communication/editor.ts b/frontend/src/wasm-communication/editor.ts index 2cfa2bba..dec09025 100644 --- a/frontend/src/wasm-communication/editor.ts +++ b/frontend/src/wasm-communication/editor.ts @@ -19,7 +19,7 @@ export async function initWasm(): Promise { // Provide a random starter seed which must occur after initializing the WASM module, since WASM can't generate its own random numbers const randomSeed = BigInt(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)); - wasmImport?.set_random_seed(randomSeed); + wasmImport?.setRandomSeed(randomSeed); } // Should be called after running `initWasm()` and its promise resolving diff --git a/frontend/src/wasm-communication/messages.ts b/frontend/src/wasm-communication/messages.ts index 661eb5eb..4d391f4b 100644 --- a/frontend/src/wasm-communication/messages.ts +++ b/frontend/src/wasm-communication/messages.ts @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ /* eslint-disable max-classes-per-file */ import { Transform, Type, plainToClass } from "class-transformer"; @@ -26,7 +25,7 @@ export class UpdateNodeGraphVisibility extends JsMessage { export class UpdateOpenDocumentsList extends JsMessage { @Type(() => FrontendDocumentDetails) - readonly open_documents!: FrontendDocumentDetails[]; + readonly openDocuments!: FrontendDocumentDetails[]; } // Allows the auto save system to use a string for the id rather than a BigInt. @@ -36,12 +35,12 @@ export class UpdateOpenDocumentsList extends JsMessage { export abstract class DocumentDetails { readonly name!: string; - readonly is_saved!: boolean; + readonly isSaved!: boolean; readonly id!: bigint | string; get displayName(): string { - return `${this.name}${this.is_saved ? "" : "*"}`; + return `${this.name}${this.isSaved ? "" : "*"}`; } } @@ -66,12 +65,12 @@ export class IndexedDbDocumentDetails extends DocumentDetails { export class TriggerIndexedDbRemoveDocument extends JsMessage { // Use a string since IndexedDB can not use BigInts for keys @Transform(({ value }: { value: bigint }) => value.toString()) - document_id!: string; + documentId!: string; } export class UpdateInputHints extends JsMessage { @Type(() => HintInfo) - readonly hint_data!: HintData; + readonly hintData!: HintData; } export type HintData = HintGroup[]; @@ -137,11 +136,11 @@ export class Color { } export class UpdateActiveDocument extends JsMessage { - readonly document_id!: bigint; + readonly documentId!: bigint; } export class DisplayDialogPanic extends JsMessage { - readonly panic_info!: string; + readonly panicInfo!: string; readonly header!: string; @@ -245,11 +244,11 @@ interface DataBuffer { length: bigint; } -export function newUpdateDocumentLayerTreeStructure(input: { data_buffer: DataBuffer }, wasm: WasmRawInstance): UpdateDocumentLayerTreeStructure { - const pointerNum = Number(input.data_buffer.pointer); - const lengthNum = Number(input.data_buffer.length); +export function newUpdateDocumentLayerTreeStructure(input: { dataBuffer: DataBuffer }, wasm: WasmRawInstance): UpdateDocumentLayerTreeStructure { + const pointerNum = Number(input.dataBuffer.pointer); + const lengthNum = Number(input.dataBuffer.length); - const wasmMemoryBuffer = wasm.wasm_memory().buffer; + const wasmMemoryBuffer = wasm.wasmMemory().buffer; // Decode the folder structure encoding const encoding = new DataView(wasmMemoryBuffer, pointerNum, lengthNum); @@ -302,9 +301,9 @@ export function newUpdateDocumentLayerTreeStructure(input: { data_buffer: DataBu export class DisplayEditableTextbox extends JsMessage { readonly text!: string; - readonly line_width!: undefined | number; + readonly lineWidth!: undefined | number; - readonly font_size!: number; + readonly fontSize!: number; @Type(() => Color) readonly color!: Color; @@ -312,7 +311,7 @@ export class DisplayEditableTextbox extends JsMessage { export class UpdateImageData extends JsMessage { @Type(() => ImageData) - readonly image_data!: ImageData[]; + readonly imageData!: ImageData[]; } export class DisplayRemoveEditableTextbox extends JsMessage {} @@ -327,13 +326,13 @@ export class LayerPanelEntry { visible!: boolean; - layer_type!: LayerType; + layerType!: LayerType; @Transform(({ value }: { value: bigint[] }) => new BigUint64Array(value)) path!: BigUint64Array; @Type(() => LayerMetadata) - layer_metadata!: LayerMetadata; + layerMetadata!: LayerMetadata; thumbnail!: string; } @@ -351,22 +350,22 @@ export class ImageData { readonly mime!: string; - readonly image_data!: Uint8Array; + readonly imageData!: Uint8Array; } export class DisplayDialogDismiss extends JsMessage {} export class Font { - font_family!: string; + fontFamily!: string; - font_style!: string; + fontStyle!: string; } export class TriggerFontLoad extends JsMessage { @Type(() => Font) font!: Font; - is_default!: boolean; + isDefault!: boolean; } export class TriggerVisitLink extends JsMessage { @@ -376,11 +375,11 @@ export class TriggerVisitLink extends JsMessage { export class TriggerTextCommit extends JsMessage {} export class TriggerTextCopy extends JsMessage { - readonly copy_text!: string; + readonly copyText!: string; } export class TriggerAboutGraphiteLocalizedCommitDate extends JsMessage { - readonly commit_date!: string; + readonly commitDate!: string; } export class TriggerViewportResize extends JsMessage {} @@ -647,13 +646,13 @@ function hoistWidgetHolders(widgetHolders: any[]): Widget[] { // WIDGET LAYOUT export interface WidgetLayout { - layout_target: unknown; + layoutTarget: unknown; layout: LayoutGroup[]; } export function defaultWidgetLayout(): WidgetLayout { return { - layout_target: null, + layoutTarget: null, layout: [], }; } @@ -708,7 +707,7 @@ function createWidgetLayout(widgetLayout: any[]): LayoutGroup[] { // WIDGET LAYOUTS export class UpdateDialogDetails extends JsMessage implements WidgetLayout { - layout_target!: unknown; + layoutTarget!: unknown; // TODO: Replace `any` with correct typing // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -717,7 +716,7 @@ export class UpdateDialogDetails extends JsMessage implements WidgetLayout { } export class UpdateDocumentModeLayout extends JsMessage implements WidgetLayout { - layout_target!: unknown; + layoutTarget!: unknown; // TODO: Replace `any` with correct typing // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -726,7 +725,7 @@ export class UpdateDocumentModeLayout extends JsMessage implements WidgetLayout } export class UpdateToolOptionsLayout extends JsMessage implements WidgetLayout { - layout_target!: unknown; + layoutTarget!: unknown; // TODO: Replace `any` with correct typing // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -735,7 +734,7 @@ export class UpdateToolOptionsLayout extends JsMessage implements WidgetLayout { } export class UpdateDocumentBarLayout extends JsMessage implements WidgetLayout { - layout_target!: unknown; + layoutTarget!: unknown; // TODO: Replace `any` with correct typing // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -744,7 +743,7 @@ export class UpdateDocumentBarLayout extends JsMessage implements WidgetLayout { } export class UpdateToolShelfLayout extends JsMessage implements WidgetLayout { - layout_target!: unknown; + layoutTarget!: unknown; // TODO: Replace `any` with correct typing // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -753,7 +752,7 @@ export class UpdateToolShelfLayout extends JsMessage implements WidgetLayout { } export class UpdateWorkingColorsLayout extends JsMessage implements WidgetLayout { - layout_target!: unknown; + layoutTarget!: unknown; // TODO: Replace `any` with correct typing // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -762,7 +761,7 @@ export class UpdateWorkingColorsLayout extends JsMessage implements WidgetLayout } export class UpdatePropertyPanelOptionsLayout extends JsMessage implements WidgetLayout { - layout_target!: unknown; + layoutTarget!: unknown; // TODO: Replace `any` with correct typing // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -771,7 +770,7 @@ export class UpdatePropertyPanelOptionsLayout extends JsMessage implements Widge } export class UpdatePropertyPanelSectionsLayout extends JsMessage implements WidgetLayout { - layout_target!: unknown; + layoutTarget!: unknown; // TODO: Replace `any` with correct typing // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -780,7 +779,7 @@ export class UpdatePropertyPanelSectionsLayout extends JsMessage implements Widg } export class UpdateLayerTreeOptionsLayout extends JsMessage implements WidgetLayout { - layout_target!: unknown; + layoutTarget!: unknown; // TODO: Replace `any` with correct typing // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -789,7 +788,7 @@ export class UpdateLayerTreeOptionsLayout extends JsMessage implements WidgetLay } export class UpdateMenuBarLayout extends JsMessage { - layout_target!: unknown; + layoutTarget!: unknown; // TODO: Replace `any` with correct typing // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/frontend/vue.config.js b/frontend/vue.config.js index 9c8e99f5..81ec0cea 100644 --- a/frontend/vue.config.js +++ b/frontend/vue.config.js @@ -11,7 +11,7 @@ module.exports = { chainWebpack: (config) => { // WASM Pack Plugin integrates compiled Rust code (.wasm) and generated wasm-bindgen code (.js) with the webpack bundle // Use this JS to import the bundled Rust entry points: const wasm = import("@/../wasm/pkg").then(panicProxy); - // Then call WASM functions with: (await wasm).function_name() + // Then call WASM functions with: (await wasm).functionName() // https://github.com/wasm-tool/wasm-pack-plugin config // https://cli.vuejs.org/guide/webpack.html#modifying-options-of-a-plugin diff --git a/frontend/wasm/src/editor_api.rs b/frontend/wasm/src/editor_api.rs index 9ecbc66d..6d22bc42 100644 --- a/frontend/wasm/src/editor_api.rs +++ b/frontend/wasm/src/editor_api.rs @@ -23,13 +23,13 @@ use wasm_bindgen::prelude::*; /// Set the random seed used by the editor by calling this from JS upon initialization. /// This is necessary because WASM doesn't have a random number generator. -#[wasm_bindgen] +#[wasm_bindgen(js_name = setRandomSeed)] pub fn set_random_seed(seed: u64) { editor::application::set_uuid_seed(seed); } /// Provides a handle to access the raw WASM memory -#[wasm_bindgen] +#[wasm_bindgen(js_name = wasmMemory)] pub fn wasm_memory() -> JsValue { wasm_bindgen::memory() } @@ -111,6 +111,7 @@ impl JsEditorHandle { // the backend from the web frontend. // ======================================================================== + #[wasm_bindgen(js_name = initAfterFrontendReady)] pub fn init_after_frontend_ready(&self, platform: String) { let platform = match platform.as_str() { "Windows" => Platform::Windows, @@ -124,29 +125,32 @@ impl JsEditorHandle { } /// Displays a dialog with an error message + #[wasm_bindgen(js_name = errorDialog)] pub fn error_dialog(&self, title: String, description: String) { let message = DialogMessage::DisplayDialogError { title, description }; self.dispatch(message); } /// Answer whether or not the editor has crashed + #[wasm_bindgen(js_name = hasCrashed)] pub fn has_crashed(&self) -> bool { EDITOR_HAS_CRASHED.load(Ordering::SeqCst) } /// Get the constant `FILE_SAVE_SUFFIX` - #[wasm_bindgen] + #[wasm_bindgen(js_name = fileSaveSuffix)] pub fn file_save_suffix(&self) -> String { FILE_SAVE_SUFFIX.into() } /// Get the constant `GRAPHITE_DOCUMENT_VERSION` - #[wasm_bindgen] + #[wasm_bindgen(js_name = graphiteDocumentVersion)] pub fn graphite_document_version(&self) -> String { GRAPHITE_DOCUMENT_VERSION.to_string() } /// Update layout of a given UI + #[wasm_bindgen(js_name = updateLayout)] pub fn update_layout(&self, layout_target: JsValue, widget_id: u64, value: JsValue) -> Result<(), JsValue> { match (from_value(layout_target), from_value(value)) { (Ok(layout_target), Ok(value)) => { @@ -158,21 +162,25 @@ impl JsEditorHandle { } } + #[wasm_bindgen(js_name = selectDocument)] pub fn select_document(&self, document_id: u64) { let message = PortfolioMessage::SelectDocument { document_id }; self.dispatch(message); } + #[wasm_bindgen(js_name = newDocumentDialog)] pub fn new_document_dialog(&self) { let message = DialogMessage::RequestNewDocumentDialog; self.dispatch(message); } + #[wasm_bindgen(js_name = documentOpen)] pub fn document_open(&self) { let message = PortfolioMessage::OpenDocument; self.dispatch(message); } + #[wasm_bindgen(js_name = openDocumentFile)] pub fn open_document_file(&self, document_name: String, document_serialized_content: String) { let message = PortfolioMessage::OpenDocumentFile { document_name, @@ -181,6 +189,7 @@ impl JsEditorHandle { self.dispatch(message); } + #[wasm_bindgen(js_name = openAutoSavedDocument)] pub fn open_auto_saved_document(&self, document_id: u64, document_name: String, document_is_saved: bool, document_serialized_content: String) { let message = PortfolioMessage::OpenDocumentFileWithId { document_id, @@ -191,21 +200,25 @@ impl JsEditorHandle { self.dispatch(message); } + #[wasm_bindgen(js_name = triggerAutoSave)] pub fn trigger_auto_save(&self, document_id: u64) { let message = PortfolioMessage::AutoSaveDocument { document_id }; self.dispatch(message); } + #[wasm_bindgen(js_name = closeDocumentWithConfirmation)] pub fn close_document_with_confirmation(&self, document_id: u64) { let message = PortfolioMessage::CloseDocumentWithConfirmation { document_id }; self.dispatch(message); } + #[wasm_bindgen(js_name = requestAboutGraphiteDialogWithLocalizedCommitDate)] pub fn request_about_graphite_dialog_with_localized_commit_date(&self, localized_commit_date: String) { let message = DialogMessage::RequestAboutGraphiteDialogWithLocalizedCommitDate { localized_commit_date }; self.dispatch(message); } + #[wasm_bindgen(js_name = requestComingSoonDialog)] pub fn request_coming_soon_dialog(&self, issue: Option) { let message = DialogMessage::RequestComingSoonDialog { issue }; self.dispatch(message); @@ -213,6 +226,7 @@ impl JsEditorHandle { /// Send new bounds when document panel viewports get resized or moved within the editor /// [left, top, right, bottom]... + #[wasm_bindgen(js_name = boundsOfViewports)] pub fn bounds_of_viewports(&self, bounds_of_viewports: &[f64]) { let chunked: Vec<_> = bounds_of_viewports.chunks(4).map(ViewportBounds::from_slice).collect(); @@ -221,6 +235,7 @@ impl JsEditorHandle { } /// Mouse movement within the screenspace bounds of the viewport + #[wasm_bindgen(js_name = onMouseMove)] pub fn on_mouse_move(&self, x: f64, y: f64, mouse_keys: u8, modifiers: u8) { let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into()); @@ -231,6 +246,7 @@ impl JsEditorHandle { } /// Mouse scrolling within the screenspace bounds of the viewport + #[wasm_bindgen(js_name = onWheelScroll)] pub fn on_wheel_scroll(&self, x: f64, y: f64, mouse_keys: u8, wheel_delta_x: i32, wheel_delta_y: i32, wheel_delta_z: i32, modifiers: u8) { let mut editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into()); editor_mouse_state.scroll_delta = ScrollDelta::new(wheel_delta_x, wheel_delta_y, wheel_delta_z); @@ -242,6 +258,7 @@ impl JsEditorHandle { } /// A mouse button depressed within screenspace the bounds of the viewport + #[wasm_bindgen(js_name = onMouseDown)] pub fn on_mouse_down(&self, x: f64, y: f64, mouse_keys: u8, modifiers: u8) { let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into()); @@ -252,6 +269,7 @@ impl JsEditorHandle { } /// A mouse button released + #[wasm_bindgen(js_name = onMouseUp)] pub fn on_mouse_up(&self, x: f64, y: f64, mouse_keys: u8, modifiers: u8) { let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into()); @@ -262,6 +280,7 @@ impl JsEditorHandle { } /// Mouse double clicked + #[wasm_bindgen(js_name = onDoubleClick)] pub fn on_double_click(&self, x: f64, y: f64, mouse_keys: u8, modifiers: u8) { let editor_mouse_state = EditorMouseState::from_keys_and_editor_position(mouse_keys, (x, y).into()); let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys"); @@ -271,6 +290,7 @@ impl JsEditorHandle { } /// A keyboard button depressed within screenspace the bounds of the viewport + #[wasm_bindgen(js_name = onKeyDown)] pub fn on_key_down(&self, name: String, modifiers: u8) { let key = translate_key(&name); let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys"); @@ -282,6 +302,7 @@ impl JsEditorHandle { } /// A keyboard button released + #[wasm_bindgen(js_name = onKeyUp)] pub fn on_key_up(&self, name: String, modifiers: u8) { let key = translate_key(&name); let modifier_keys = ModifierKeys::from_bits(modifiers).expect("Invalid modifier keys"); @@ -293,6 +314,7 @@ impl JsEditorHandle { } /// A text box was committed + #[wasm_bindgen(js_name = onChangeText)] pub fn on_change_text(&self, new_text: String) -> Result<(), JsValue> { let message = TextToolMessage::TextChange { new_text }; self.dispatch(message); @@ -301,6 +323,7 @@ impl JsEditorHandle { } /// A font has been downloaded + #[wasm_bindgen(js_name = onFontLoad)] pub fn on_font_load(&self, font_family: String, font_style: String, preview_url: String, data: Vec, is_default: bool) -> Result<(), JsValue> { let message = PortfolioMessage::FontLoaded { font_family, @@ -315,6 +338,7 @@ impl JsEditorHandle { } /// A text box was changed + #[wasm_bindgen(js_name = updateBounds)] pub fn update_bounds(&self, new_text: String) -> Result<(), JsValue> { let message = TextToolMessage::UpdateBounds { new_text }; self.dispatch(message); @@ -323,6 +347,7 @@ impl JsEditorHandle { } /// Update primary color + #[wasm_bindgen(js_name = updatePrimaryColor)] pub fn update_primary_color(&self, red: f32, green: f32, blue: f32, alpha: f32) -> Result<(), JsValue> { let primary_color = match Color::from_rgbaf32(red, green, blue, alpha) { Some(color) => color, @@ -336,6 +361,7 @@ impl JsEditorHandle { } /// Update secondary color + #[wasm_bindgen(js_name = updateSecondaryColor)] pub fn update_secondary_color(&self, red: f32, green: f32, blue: f32, alpha: f32) -> Result<(), JsValue> { let secondary_color = match Color::from_rgbaf32(red, green, blue, alpha) { Some(color) => color, @@ -349,24 +375,28 @@ impl JsEditorHandle { } /// Paste layers from a serialized json representation + #[wasm_bindgen(js_name = pasteSerializedData)] pub fn paste_serialized_data(&self, data: String) { let message = PortfolioMessage::PasteSerializedData { data }; self.dispatch(message); } /// Modify the layer selection based on the layer which is clicked while holding down the Ctrl and/or Shift modifier keys used for range selection behavior + #[wasm_bindgen(js_name = selectLayer)] pub fn select_layer(&self, layer_path: Vec, ctrl: bool, shift: bool) { let message = DocumentMessage::SelectLayer { layer_path, ctrl, shift }; self.dispatch(message); } /// Deselect all layers + #[wasm_bindgen(js_name = deselectAllLayers)] pub fn deselect_all_layers(&self) { let message = DocumentMessage::DeselectAllLayers; self.dispatch(message); } /// Move a layer to be next to the specified neighbor + #[wasm_bindgen(js_name = moveLayerInTree)] pub fn move_layer_in_tree(&self, folder_path: Vec, insert_index: isize) { let message = DocumentMessage::MoveSelectedLayersTo { folder_path, @@ -377,24 +407,28 @@ impl JsEditorHandle { } /// Set the name for the layer + #[wasm_bindgen(js_name = setLayerName)] pub fn set_layer_name(&self, layer_path: Vec, name: String) { let message = DocumentMessage::SetLayerName { layer_path, name }; self.dispatch(message); } /// Translates document (in viewport coords) + #[wasm_bindgen(js_name = translateCanvas)] pub fn translate_canvas(&self, delta_x: f64, delta_y: f64) { let message = NavigationMessage::TranslateCanvas { delta: (delta_x, delta_y).into() }; self.dispatch(message); } /// Translates document (in viewport coords) + #[wasm_bindgen(js_name = translateCanvasByFraction)] pub fn translate_canvas_by_fraction(&self, delta_x: f64, delta_y: f64) { let message = NavigationMessage::TranslateCanvasByViewportFraction { delta: (delta_x, delta_y).into() }; self.dispatch(message); } /// Sends the blob url generated by js + #[wasm_bindgen(js_name = setImageBlobUrl)] pub fn set_image_blob_url(&self, path: Vec, blob_url: String, width: f64, height: f64) { let dimensions = (width, height); let message = Operation::SetImageBlobUrl { path, blob_url, dimensions }; @@ -402,6 +436,7 @@ impl JsEditorHandle { } /// Pastes an image + #[wasm_bindgen(js_name = pasteImage)] pub fn paste_image(&self, mime: String, image_data: Vec, mouse_x: Option, mouse_y: Option) { let mouse = mouse_x.and_then(|x| mouse_y.map(|y| (x, y))); let message = DocumentMessage::PasteImage { mime, image_data, mouse }; @@ -409,12 +444,14 @@ impl JsEditorHandle { } /// Toggle visibility of a layer from the layer list + #[wasm_bindgen(js_name = toggleLayerVisibility)] pub fn toggle_layer_visibility(&self, layer_path: Vec) { let message = DocumentMessage::ToggleLayerVisibility { layer_path }; self.dispatch(message); } /// Toggle expansions state of a layer from the layer list + #[wasm_bindgen(js_name = toggleLayerExpansion)] pub fn toggle_layer_expansion(&self, layer_path: Vec) { let message = DocumentMessage::ToggleLayerExpansion { layer_path }; self.dispatch(message); diff --git a/graphene/src/layers/text_layer/font_cache.rs b/graphene/src/layers/text_layer/font_cache.rs index 343d6fc0..ee546700 100644 --- a/graphene/src/layers/text_layer/font_cache.rs +++ b/graphene/src/layers/text_layer/font_cache.rs @@ -4,7 +4,9 @@ use std::collections::HashMap; /// A font type (storing font family and font style and an optional preview URL) #[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)] pub struct Font { + #[serde(rename = "fontFamily")] pub font_family: String, + #[serde(rename = "fontStyle")] pub font_style: String, } impl Font { diff --git a/website/content/features/_index.md b/website/content/features/_index.md index ba385a2d..58618525 100644 --- a/website/content/features/_index.md +++ b/website/content/features/_index.md @@ -3,7 +3,7 @@ title = "Features and roadmap" template = "page.html" +++ -This page is a work in progress. Below is an incomplete list of planned features in no particular order. Many are long-term aspirations. In the coming days, this will be sequenced into a roadmap and expanded with further details. +This page is a work in progress. Below is an incomplete list of planned features in no particular order. Many are long-term aspirations. Soon, this will be sequenced into a roadmap and expanded with further details. Short-term feature development at a more granular level is tracked in the [Task Board](https://github.com/GraphiteEditor/Graphite/projects/1) on GitHub. Check that out to see what's coming down the pipeline during monthly sprints.