Advertisement
Guest User

Untitled

a guest
Feb 19th, 2017
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 155.74 KB | None | 0 0
  1. local sheets
  2. local __debug_err_map={
  3.  
  4. }
  5. local __debug_err_pats={
  6. ["lua.arithmetic"]={{"attempt to perform arithmetic __(%w+) on (%w+) and (%w+)","failed to %1 ${1} (%2) and ${2} (%3)"}}
  7. }
  8. local __debug_line_tracker={
  9. {119,122,"main",1},
  10. {123,141,"/sheets/src/v0.0.4/sheets",1},
  11. {142,261,"constants",1},
  12. {262,318,"/sheets/src/v0.0.4/sheets",20},
  13. {319,543,".sheets.lib.class",1},
  14. {544,544,"/sheets/src/v0.0.4/sheets",77},
  15. {545,565,"lib.clipboard",1},
  16. {566,566,"/sheets/src/v0.0.4/sheets",78},
  17. {567,609,"lib.parameters",1},
  18. {610,611,"/sheets/src/v0.0.4/sheets",79},
  19. {612,1902,"surface2",1},
  20. {1903,1904,"/sheets/src/v0.0.4/sheets",81},
  21. {1905,1929,"enum.Easing",1},
  22. {1930,1931,"/sheets/src/v0.0.4/sheets",83},
  23. {1932,2035,"exceptions.Exception",1},
  24. {2036,2036,"/sheets/src/v0.0.4/sheets",85},
  25. {2037,2046,"exceptions.IncorrectParameterException",1},
  26. {2047,2047,"/sheets/src/v0.0.4/sheets",86},
  27. {2048,2057,"exceptions.IncorrectConstructorException",1},
  28. {2058,2058,"/sheets/src/v0.0.4/sheets",87},
  29. {2059,2068,"exceptions.ResourceLoadException",1},
  30. {2069,2069,"/sheets/src/v0.0.4/sheets",88},
  31. {2070,2079,"exceptions.ThreadRuntimeException",1},
  32. {2080,2081,"/sheets/src/v0.0.4/sheets",89},
  33. {2082,2145,"interfaces.ICollatedChildren",1},
  34. {2146,2146,"/sheets/src/v0.0.4/sheets",91},
  35. {2147,2156,"interfaces.IColoured",1},
  36. {2157,2157,"/sheets/src/v0.0.4/sheets",92},
  37. {2158,2292,"interfaces.IQueryable",1},
  38. {2293,2293,"/sheets/src/v0.0.4/sheets",93},
  39. {2294,2449,"interfaces.IChildContainer",1},
  40. {2450,2450,"/sheets/src/v0.0.4/sheets",94},
  41. {2451,2535,"interfaces.ITagged",1},
  42. {2536,2536,"/sheets/src/v0.0.4/sheets",95},
  43. {2537,2548,"interfaces.ISize",1},
  44. {2549,2549,"/sheets/src/v0.0.4/sheets",96},
  45. {2550,2623,"interfaces.ITimer",1},
  46. {2624,2625,"/sheets/src/v0.0.4/sheets",97},
  47. {2626,2640,"events.Event",1},
  48. {2641,2641,"/sheets/src/v0.0.4/sheets",99},
  49. {2642,2687,"events.KeyboardEvent",1},
  50. {2688,2688,"/sheets/src/v0.0.4/sheets",100},
  51. {2689,2700,"events.MiscEvent",1},
  52. {2701,2701,"/sheets/src/v0.0.4/sheets",101},
  53. {2702,2747,"events.MouseEvent",1},
  54. {2748,2748,"/sheets/src/v0.0.4/sheets",102},
  55. {2749,2760,"events.TextEvent",1},
  56. {2761,2762,"/sheets/src/v0.0.4/sheets",103},
  57. {2763,3785,"dynamic.Codegen",1},
  58. {3786,3786,"/sheets/src/v0.0.4/sheets",105},
  59. {3787,4156,"dynamic.DynamicValueParser",1},
  60. {4157,4157,"/sheets/src/v0.0.4/sheets",106},
  61. {4158,4302,"dynamic.QueryTracker",1},
  62. {4303,4303,"/sheets/src/v0.0.4/sheets",107},
  63. {4304,4519,"dynamic.Stream",1},
  64. {4520,4520,"/sheets/src/v0.0.4/sheets",108},
  65. {4521,4550,"dynamic.Transition",1},
  66. {4551,4551,"/sheets/src/v0.0.4/sheets",109},
  67. {4552,4661,"dynamic.Type",1},
  68. {4662,4662,"/sheets/src/v0.0.4/sheets",110},
  69. {4663,4929,"dynamic.Typechecking",1},
  70. {4930,4930,"/sheets/src/v0.0.4/sheets",111},
  71. {4931,5187,"dynamic.ValueHandler",1},
  72. {5188,5189,"/sheets/src/v0.0.4/sheets",112},
  73. {5190,5621,"core.Application",1},
  74. {5622,5622,"/sheets/src/v0.0.4/sheets",114},
  75. {5623,5797,"core.Screen",1},
  76. {5798,5798,"/sheets/src/v0.0.4/sheets",115},
  77. {5799,5929,"core.Sheet",1},
  78. {5930,5932,"/sheets/src/v0.0.4/sheets",116},
  79. {5933,5986,"core.Thread",1},
  80. {5987,5989,"/sheets/src/v0.0.4/sheets",119},
  81. {5990,6090,"elements.Container",1},
  82. {6091,6093,"/sheets/src/v0.0.4/sheets",122},
  83. {6094,6190,"interfaces.IHasText",1},
  84. {6191,6191,"/sheets/src/v0.0.4/sheets",125},
  85. {6192,6250,"elements.Button",1},
  86. {6251,6256,"/sheets/src/v0.0.4/sheets",126},
  87. {6257,6307,"elements.ClippedContainer",1},
  88. {6308,6317,"/sheets/src/v0.0.4/sheets",132},
  89. {6318,6447,"elements.KeyHandler",1},
  90. {6448,6450,"/sheets/src/v0.0.4/sheets",142},
  91. {6451,6466,"elements.Panel",1},
  92. {6467,6477,"/sheets/src/v0.0.4/sheets",145},
  93. {6479,6482,"main",5}
  94. }
  95. local function __get_src_and_line( line )
  96. for i = 1, #__debug_line_tracker do
  97. local t = __debug_line_tracker[i]
  98. if line >= t[1] and line <= t[2] then
  99. return t[3], t[4] + line - t[1]
  100. end
  101. end
  102. return "unknown source", 0
  103. end
  104. local function __get_err_msg( src, line, err )
  105. if __debug_err_map[src] and __debug_err_map[src][line] then
  106. local name = __debug_err_map[src][line][1]
  107. for i = 1, #__debug_err_pats[name] do
  108. local data, r = err:gsub( __debug_err_pats[name][i][1], __debug_err_pats[name][i][2]:gsub( "%$%{(%d+)%}", function( n )
  109. return __debug_err_map[src][line][tonumber( n ) + 1]
  110. end ), 1 )
  111. if r > 0 then
  112. return data
  113. end
  114. end
  115. end
  116. return err
  117. end
  118. local ok, err = pcall( function()
  119.  
  120.  
  121.  
  122. do sheets={}local KeyHandler,ICollatedChildren,KeyboardEvent,Exception,Event,ITimer,class,QueryTracker,Stream,Transition,Application,IQueryable,ThreadRuntimeException,Button,MouseEvent,ClippedContainer,ISize,TableType,Easing,MiscEvent,IColoured,Thread,Container,TextEvent,parameters,Panel,ResourceLoadException,Codegen,Typechecking,UnionType,ValueHandler,IncorrectParameterException,DynamicValueParser,Sheet,IHasText,Screen,Type,IChildContainer,IncorrectConstructorException,ListType,clipboard,ITagged
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147.  
  148.  
  149.  
  150.  
  151.  
  152.  
  153.  
  154.  
  155.  
  156.  
  157.  
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.  
  208.  
  209.  
  210.  
  211.  
  212.  
  213.  
  214.  
  215.  
  216.  
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226.  
  227.  
  228.  
  229.  
  230.  
  231.  
  232.  
  233.  
  234.  
  235.  
  236.  
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245.  
  246.  
  247.  
  248.  
  249.  
  250.  
  251.  
  252.  
  253.  
  254.  
  255.  
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263. event={
  264. mouse_down=0;
  265. mouse_up=1;
  266. mouse_click=2;
  267. mouse_hold=3;
  268. mouse_drag=4;
  269. mouse_scroll=5;
  270. mouse_ping=6;
  271. key_down=7;
  272. key_up=8;
  273. text=9;
  274. voice=10;
  275. paste=11;
  276. }
  277.  
  278. alignment={
  279. left=0;
  280. centre=1;
  281. center=1;
  282. right=2;
  283. top=3;
  284. bottom=4;
  285. }
  286.  
  287. colour={
  288. transparent=0;
  289. white=1;
  290. orange=2;
  291. magenta=4;
  292. light_blue=8;
  293. yellow=16;
  294. lime=32;
  295. pink=64;
  296. grey=128;
  297. light_grey=256;
  298. cyan=512;
  299. purple=1024;
  300. blue=2048;
  301. brown=4096;
  302. green=8192;
  303. red=16384;
  304. black=32768;
  305. }
  306.  
  307. token={
  308. eof="eof";
  309. string="string";
  310. float="float";
  311. int=TOKEN_INT;
  312. ident=TOKEN_IDENT;
  313. newline="newline";
  314. symbol="symbol";
  315. operator=TOKEN_OPERATOR;
  316. }
  317.  
  318.  
  319.  
  320.  
  321. class={}
  322.  
  323. local classobj=setmetatable({},{__index=class})
  324. local supported_meta_methods={__add=true,__sub=true,__mul=true,__div=true,__mod=true,__pow=true,__unm=true,__len=true,__eq=true,__lt=true,__lte=true,__tostring=true,__concat=true}
  325.  
  326. local function _tostring(self)
  327. return"[Class] "..self:type()
  328. end
  329.  
  330. local function _concat(a,b)
  331. return tostring(a)..tostring(b)
  332. end
  333.  
  334. local function _instance_tostring(self)
  335. return"[Instance] "..self:type()
  336. end
  337.  
  338. local function new_super(object,super)
  339.  
  340. local super_proxy={}
  341.  
  342. if super.super then
  343. super_proxy.super=new_super(object,super.super)
  344. end
  345.  
  346. setmetatable(super_proxy,{__index=function(t,k)
  347.  
  348. if type(super[k])=="function"then
  349. return function(self,...)
  350.  
  351. if self==super_proxy then
  352. self=object
  353. end
  354. object.super=super_proxy.super
  355. local v={super[k](self,...)}
  356. object.super=super_proxy
  357. return unpack(v)
  358.  
  359. end
  360. else
  361. return super[k]
  362. end
  363.  
  364. end,__newindex=super,__tostring=function(self)
  365. return"[Super] "..tostring(super).." of "..tostring(object)
  366. end})
  367.  
  368. return super_proxy
  369.  
  370. end
  371.  
  372. function classobj:new(...)
  373.  
  374. local mt={__index=self,__INSTANCE=true}
  375. local instance=setmetatable({class=self,meta=mt},mt)
  376.  
  377. if self.super then
  378. instance.super=new_super(instance,self.super)
  379. end
  380.  
  381. for k,v in pairs(self.meta)do
  382. if supported_meta_methods[k]then
  383. mt[k]=v
  384. end
  385. end
  386.  
  387. if mt.__tostring==_tostring then
  388. function mt:__tostring()
  389. return self:tostring()
  390. end
  391. end
  392.  
  393. function instance:type()
  394. return self.class:type()
  395. end
  396.  
  397. function instance:type_of(class)
  398. return self.class:type_of(class)
  399. end
  400.  
  401. function instance:implements(interface)
  402. return self.class:implements(interface)
  403. end
  404.  
  405. if not self.tostring then
  406. instance.tostring=_instance_tostring
  407. end
  408.  
  409. local ob=self
  410. while ob do
  411. if ob[ob.meta.__type]then
  412. ob[ob.meta.__type](instance,...)
  413. break
  414. end
  415. ob=ob.super
  416. end
  417.  
  418. return instance
  419.  
  420. end
  421.  
  422. function classobj:type()
  423. return tostring(self.meta.__type)
  424. end
  425.  
  426. function classobj:type_of(super)
  427. return super==self or(self.super and self.super:type_of(super))or false
  428. end
  429.  
  430. function classobj:implements(interface)
  431. return self.__interface_list[interface]==true
  432. end
  433.  
  434. function class.new(name,super,...)
  435. local implements={...}
  436. local len=#implements
  437. local implements_lookup={}
  438.  
  439. if type(name)~="string"then
  440. return error("expected string class name, got "..type(name))
  441. end
  442.  
  443. local mt={__index=classobj,__CLASS=true,__tostring=_tostring,__concat=_concat,__call=classobj.new,__type=name}
  444. local obj=setmetatable({meta=mt,__interface_list=implements_lookup},mt)
  445.  
  446. if super then
  447. obj.super=super
  448. obj.meta.__index=super
  449.  
  450. for interface in pairs(super.__interface_list)do
  451. implements_lookup[interface]=true
  452. end
  453. end
  454.  
  455. for i=1,len do
  456. implements_lookup[implements[i]]=true
  457. for k,v in pairs(implements[i])do
  458. if k~="__interface_list"then
  459. obj[k]=v
  460. end
  461. end
  462. for interface in pairs(implements[i].__interface_list)do
  463. implements_lookup[interface]=true
  464. end
  465. end
  466.  
  467. return function(t)
  468. for k,v in pairs(t)do
  469. obj[k]=v
  470. end
  471. return obj
  472. end
  473. end
  474.  
  475. function class.type(object)
  476. local _type=type(object)
  477.  
  478. if _type=="table"then
  479. pcall(function()
  480. local mt=getmetatable(object)
  481. _type=((mt.__CLASS or mt.__INSTANCE)and object:type())or _type
  482. end)
  483. end
  484.  
  485. return _type
  486. end
  487.  
  488. function class.type_of(object,class)
  489. if type(object)=="table"then
  490. local ok,v=pcall(function()
  491. return getmetatable(object).__CLASS or getmetatable(object).__INSTANCE or error()
  492. end)
  493. return ok and object:type_of(class)
  494. end
  495.  
  496. return false
  497. end
  498.  
  499. function class.is_class(object)
  500. return pcall(function()if not getmetatable(object).__CLASS then error()end end),nil
  501. end
  502.  
  503. function class.is_instance(object)
  504. return pcall(function()if not getmetatable(object).__INSTANCE then error()end end),nil
  505. end
  506.  
  507. setmetatable(class,{
  508. __call=class.new;
  509. })
  510.  
  511. function class.new_interface(name,...)
  512. local implements={...}
  513. local implements_lookup={}
  514. local obj={__interface_list=implements_lookup}
  515. local len=#implements
  516.  
  517. for i=1,len do
  518. implements_lookup[implements[i]]=true
  519. for k,v in pairs(implements[i])do
  520. if k~="__interface_list"then
  521. obj[k]=v
  522. end
  523. end
  524. for interface in pairs(implements[i].__interface_list)do
  525. implements_lookup[interface]=true
  526. end
  527. end
  528.  
  529. return function(t)
  530. for k,v in pairs(t)do
  531. obj[k]=v
  532. end
  533. return obj
  534. end
  535. end
  536.  
  537. function class.new_enum(name)
  538. return function(t)
  539. return setmetatable({},{__index=t,__newindex=function(t,k,v)
  540. return error("attempt to set enum index '"..tostring(k).."'" )
  541. end } )
  542. end
  543. end
  544.  
  545.  
  546.  
  547.  
  548.  
  549. local c = {}
  550.  
  551. clipboard = {}
  552.  
  553. function clipboard.put( modes )
  554. parameters.check( 1, "modes", "table", modes )
  555. c = modes
  556. end
  557.  
  558. function clipboard.get( mode )
  559. parameters.check( 1, "mode", "string", mode )
  560. return c[mode]
  561. end
  562.  
  563. function clipboard.clear()
  564. c = {}
  565. end
  566.  
  567.  
  568.  
  569.  
  570.  
  571. parameters = {}
  572.  
  573. function parameters.check_constructor( _class, argc, ... )
  574. local args = { ... }
  575. for i = 1, argc * 3, 3 do
  576. local name = args[i]
  577. local expected_type = args[i + 1]
  578. local value = args[i + 2]
  579.  
  580. if type( expected_type ) == "string" then
  581. if type( value ) ~= expected_type then
  582. Exception.throw( IncorrectConstructorException, _class:type() .. " expects " .. expected_type .. " " .. name .. " when created, got " .. class.type( value ), 4 )
  583. end
  584. else
  585. if not class.type_of( value, expected_type ) then
  586. Exception.throw( IncorrectConstructorException, _class:type() .. " expects " .. expected_type:type() .. " " .. name .. " when created, got " .. class.type( value ), 4 )
  587. end
  588. end
  589. end
  590. end
  591.  
  592. function parameters.check( argc, ... )
  593. local args = { ... }
  594. for i = 1, argc * 3, 3 do
  595. local name = args[i]
  596. local expected_type = args[i + 1]
  597. local value = args[i + 2]
  598.  
  599. if type( expected_type ) == "string" then
  600. if type( value ) ~= expected_type then
  601. Exception.throw( IncorrectParameterException, "expected " .. expected_type .. " " .. name .. ", got " .. class.type( value ), 3 )
  602. end
  603. else
  604. if not class.type_of( value, expected_type ) then
  605. Exception.throw( IncorrectParameterException, "expected " .. expected_type:type() .. " " .. name .. ", got " .. class.type( value ), 3 )
  606. end
  607. end
  608. end
  609. end
  610.  
  611.  
  612. surface = { } do
  613. --[[
  614. Surface version 2.0.0
  615.  
  616. The MIT License (MIT)
  617. Copyright (c) 2017 CrazedProgrammer
  618.  
  619. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
  620. associated documentation files (the "Software"), to deal in the Software without restriction,
  621. table: 19526e4 without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
  622. and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do
  623. so, subject to the following conditions:
  624.  
  625. The above copyright notice and this permission notice shall be included in all copies or
  626. substantial portions of the Software.
  627.  
  628. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  629. INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  630. PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  631. COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  632. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  633. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  634. ]]
  635.  
  636. local surf = { }
  637. surface.surf = surf
  638.  
  639. local table_concat, math_floor, math_atan2 = table.concat, math.floor, math.atan2
  640.  
  641. local _cc_color_to_hex, _cc_hex_to_color = { }, { }
  642. for i = 0, 15 do
  643. _cc_color_to_hex[2 ^ i] = string.format("%01x", i)
  644. _cc_hex_to_color[string.format("%01x", i)] = 2 ^ i
  645. end
  646.  
  647. local _chars = { }
  648. for i = 0, 255 do
  649. _chars[i] = string.char(i)
  650. end
  651.  
  652. local _eprc, _esin, _ecos = 20, { }, { }
  653. for i = 0, _eprc - 1 do
  654. _esin[i + 1] = (1 - math.sin(i / _eprc * math.pi * 2)) / 2
  655. _ecos[i + 1] = (1 + math.cos(i / _eprc * math.pi * 2)) / 2
  656. end
  657.  
  658. local _steps, _palette, _rgbpal, _palr, _palg, _palb = 16
  659.  
  660. local function calcStack(stack, width, height)
  661. local ox, oy, cx, cy, cwidth, cheight = 0, 0, 0, 0, width, height
  662. for i = 1, #stack do
  663. ox = ox + stack[i].ox
  664. oy = oy + stack[i].oy
  665. cx = cx + stack[i].x
  666. cy = cy + stack[i].y
  667. cwidth = stack[i].width
  668. cheight = stack[i].height
  669. end
  670. return ox, oy, cx, cy, cwidth, cheight
  671. end
  672.  
  673. local function clipRect(x, y, width, height, cx, cy, cwidth, cheight)
  674. if x < cx then
  675. width = width + x - cx
  676. x = cx
  677. end
  678. if y < cy then
  679. height = height + y - cy
  680. y = cy
  681. end
  682. if x + width > cx + cwidth then
  683. width = cwidth + cx - x
  684. end
  685. if y + height > cy + cheight then
  686. height = cheight + cy - y
  687. end
  688. return x, y, width, height
  689. end
  690.  
  691.  
  692.  
  693. function surface.create(width, height, b, t, c)
  694. local surface = setmetatable({ }, {__index = surface.surf})
  695. surface.width = width
  696. surface.height = height
  697. surface.buffer = { }
  698. surface.overwrite = false
  699. surface.stack = { }
  700. surface.ox, surface.oy, surface.cx, surface.cy, surface.cwidth, surface.cheight = calcStack(surface.stack, width, height)
  701. -- force array indeces instead of hashed indices
  702.  
  703. local buffer = surface.buffer
  704. for i = 1, width * height * 3, 3 do
  705. buffer[i] = b or false
  706. buffer[i + 1] = t or false
  707. buffer[i + 2] = c or false
  708. end
  709. buffer[width * height * 3 + 1] = false
  710. if not b then
  711. for i = 1, width * height * 3, 3 do
  712. buffer[i] = b
  713. end
  714. end
  715. if not t then
  716. for i = 2, width * height * 3, 3 do
  717. buffer[i] = t
  718. end
  719. end
  720. if not c then
  721. for i = 3, width * height * 3, 3 do
  722. buffer[i] = c
  723. end
  724. end
  725.  
  726. return surface
  727. end
  728.  
  729. function surf:output(output, x, y, sx, sy, swidth, sheight)
  730. output = output or (term or gpu)
  731. if love then output = output or love.graphics end
  732. x = x or 0
  733. y = y or 0
  734. sx = sx or 0
  735. sy = sy or 0
  736. swidth = swidth or self.width
  737. sheight = sheight or self.height
  738. sx, sy, swidth, sheight = clipRect(sx, sy, swidth, sheight, 0, 0, self.width, self.height)
  739.  
  740. local buffer = self.buffer
  741. local bwidth = self.width
  742. local xoffset, yoffset, idx
  743.  
  744. if output.blit and output.setCursorPos then
  745. -- CC
  746. local cmd, str, text, back = { }, { }, { }, { }
  747. for j = 0, sheight - 1 do
  748. yoffset = (j + sy) * bwidth + sx
  749. for i = 0, swidth - 1 do
  750. xoffset = (yoffset + i) * 3
  751. idx = i + 1
  752. str[idx] = buffer[xoffset + 3] or " "
  753. text[idx] = _cc_color_to_hex[buffer[xoffset + 2] or 1]
  754. back[idx] = _cc_color_to_hex[buffer[xoffset + 1] or 32768]
  755. end
  756. output.setCursorPos(x + 1, y + j + 1)
  757. output.blit(table_concat(str), table_concat(text), table_concat(back))
  758. end
  759.  
  760. elseif output.write and output.setCursorPos and output.setTextColor and output.setBackgroundColor then
  761. -- CC pre-1.76
  762. local str, b, t, pb, pt = { }
  763. for j = 0, sheight - 1 do
  764. output.setCursorPos(x + 1, y + j + 1)
  765. yoffset = (j + sy) * bwidth + sx
  766. for i = 0, swidth - 1 do
  767. xoffset = (yoffset + i) * 3
  768. pb = buffer[xoffset + 1] or 32768
  769. pt = buffer[xoffset + 2] or 1
  770. if pb ~= b then
  771. if #str ~= 0 then
  772. output.write(table_concat(str))
  773. str = { }
  774. end
  775. b = pb
  776. output.setBackgroundColor(b)
  777. end
  778. if pt ~= t then
  779. if #str ~= 0 then
  780. output.write(table_concat(str))
  781. str = { }
  782. end
  783. t = pt
  784. output.setTextColor(t)
  785. end
  786. str[#str + 1] = buffer[xoffset + 3] or " "
  787. end
  788. output.write(table_concat(str))
  789. str = { }
  790. end
  791.  
  792. elseif output.blitPixels then
  793. -- Riko 4
  794. local pixels = { }
  795. for j = 0, sheight - 1 do
  796. yoffset = (j + sy) * bwidth + sx
  797. for i = 0, swidth - 1 do
  798. pixels[j * swidth + i + 1] = buffer[(yoffset + i) * 3 + 1] or 0
  799. end
  800. end
  801. output.blitPixels(x, y, swidth, sheight, pixels)
  802.  
  803. elseif output.points and output.setColor then
  804. -- Love2D
  805. local pos, r, g, b, pr, pg, pb = { }
  806. for j = 0, sheight - 1 do
  807. yoffset = (j + sy) * bwidth + sx
  808. for i = 0, swidth - 1 do
  809. xoffset = (yoffset + i) * 3
  810. pr = buffer[xoffset + 1]
  811. pg = buffer[xoffset + 2]
  812. pb = buffer[xoffset + 3]
  813. if pr ~= r or pg ~= g or pb ~= b then
  814. if #pos ~= 0 then
  815. output.setColor((r or 0) * 255, (g or 0) * 255, (b or 0) * 255, (r or g or b) and 255 or 0)
  816. output.points(pos)
  817. end
  818. r, g, b = pr, pg, pb
  819. pos = { }
  820. end
  821. pos[#pos + 1] = i + x
  822. pos[#pos + 1] = j + y
  823. end
  824. end
  825.  
  826. elseif output.drawPixel then
  827. -- Redirection arcade (gpu)
  828. -- todo: add image:write support for extra performance
  829. local px = output.drawPixel
  830. for j = 0, sheight - 1 do
  831. for i = 0, swidth - 1 do
  832. px(x + i, y + j, buffer[((j + sy) * bwidth + (i + sx)) * 3 + 1] or 0)
  833. end
  834. end
  835.  
  836. else
  837. error("unsupported output object")
  838. end
  839. end
  840.  
  841. function surf:push(x, y, width, height, nooffset)
  842. x, y = x + self.ox, y + self.oy
  843.  
  844. local ox, oy = nooffset and self.ox or x, nooffset and self.oy or y
  845. x, y, width, height = clipRect(x, y, width, height, self.cx, self.cy, self.cwidth, self.cheight)
  846. self.stack[#self.stack + 1] = {ox = ox - self.ox, oy = oy - self.oy, x = x - self.cx, y = y - self.cy, width = width, height = height}
  847.  
  848. self.ox, self.oy, self.cx, self.cy, self.cwidth, self.cheight = calcStack(self.stack, self.width, self.height)
  849. end
  850.  
  851. function surf:pop()
  852. if #self.stack == 0 then
  853. error("no stencil to pop")
  854. end
  855. self.stack[#self.stack] = nil
  856. self.ox, self.oy, self.cx, self.cy, self.cwidth, self.cheight = calcStack(self.stack, self.width, self.height)
  857. end
  858.  
  859. function surf:copy()
  860. local surface = setmetatable({ }, {__index = surface.surf})
  861.  
  862. for k, v in pairs(self) do
  863. surface[k] = v
  864. end
  865.  
  866. surface.buffer = { }
  867. for i = 1, self.width * self.height * 3 + 1 do
  868. surface.buffer[i] = false
  869. end
  870. for i = 1, self.width * self.height * 3 do
  871. surface.buffer[i] = self.buffer[i]
  872. end
  873.  
  874. surface.stack = { }
  875. for i = 1, #self.stack do
  876. surface.stack[i] = self.stack[i]
  877. end
  878.  
  879. return surface
  880. end
  881.  
  882. function surf:clear(b, t, c)
  883. local xoffset, yoffset
  884.  
  885. for j = 0, self.cheight - 1 do
  886. yoffset = (j + self.cy) * self.width + self.cx
  887. for i = 0, self.cwidth - 1 do
  888. xoffset = (yoffset + i) * 3
  889. self.buffer[xoffset + 1] = b
  890. self.buffer[xoffset + 2] = t
  891. self.buffer[xoffset + 3] = c
  892. end
  893. end
  894. end
  895.  
  896. function surf:drawPixel(x, y, b, t, c)
  897. x, y = x + self.ox, y + self.oy
  898.  
  899. local idx
  900. if x >= self.cx and x < self.cx + self.cwidth and y >= self.cy and y < self.cy + self.cheight then
  901. idx = (y * self.width + x) * 3
  902. if b or self.overwrite then
  903. self.buffer[idx + 1] = b
  904. end
  905. if t or self.overwrite then
  906. self.buffer[idx + 2] = t
  907. end
  908. if c or self.overwrite then
  909. self.buffer[idx + 3] = c
  910. end
  911. end
  912. end
  913.  
  914. function surf:drawString(x, y, str, b, t)
  915. x, y = x + self.ox, y + self.oy
  916.  
  917. local sx = x
  918. local insidey = y >= self.cy and y < self.cy + self.cheight
  919. local idx
  920. local lowerxlim = self.cx
  921. local upperxlim = self.cx + self.cwidth
  922. local writeb = b or self.overwrite
  923. local writet = t or self.overwrite
  924.  
  925. for i = 1, #str do
  926. local c = str:sub(i, i)
  927. if c == "\n" then
  928. x = sx
  929. y = y + 1
  930. if insidey then
  931. if y >= self.cy + self.cheight then
  932. return
  933. end
  934. else
  935. insidey = y >= self.cy
  936. end
  937. else
  938. idx = (y * self.width + x) * 3
  939. if x >= lowerxlim and x < upperxlim and insidey then
  940. if writeb then
  941. self.buffer[idx + 1] = b
  942. end
  943. if writet then
  944. self.buffer[idx + 2] = t
  945. end
  946. self.buffer[idx + 3] = c
  947. end
  948. x = x + 1
  949. end
  950. end
  951. end
  952.  
  953. -- You can remove any of these components
  954. function surface.load(strpath, isstr)
  955. local data = strpath
  956. if not isstr then
  957. local handle = io.open(strpath, "rb")
  958. if not handle then return end
  959. chars = { }
  960. local byte = handle:read(1)
  961. while byte do
  962. chars[#chars + 1] = _chars[byte]
  963. byte = handle:read(1)
  964. end
  965. handle:close()
  966. data = table_concat(chars)
  967. end
  968.  
  969. if data:sub(1, 3) == "RIF" then
  970. -- Riko 4 image format
  971. local width, height = data:byte(4) * 256 + data:byte(5), data:byte(6) * 256 + data:byte(7)
  972. local surf = surface.create(width, height)
  973. local buffer = surf.buffer
  974. local upper, byte = 8, false
  975. local byte = data:byte(index)
  976.  
  977. for j = 0, height - 1 do
  978. for i = 0, height - 1 do
  979. if not upper then
  980. buffer[(j * width + i) * 3 + 1] = math_floor(byte / 16)
  981. else
  982. buffer[(j * width + i) * 3 + 1] = byte % 16
  983. index = index + 1
  984. data = data:byte(index)
  985. end
  986. upper = not upper
  987. end
  988. end
  989. return surf
  990.  
  991. elseif data:sub(1, 2) == "BM" then
  992. -- BMP format
  993. local width = data:byte(0x13) + data:byte(0x14) * 256
  994. local height = data:byte(0x17) + data:byte(0x18) * 256
  995. if data:byte(0xF) ~= 0x28 or data:byte(0x1B) ~= 1 or data:byte(0x1D) ~= 0x18 then
  996. error("unsupported bmp format, only uncompressed 24-bit rgb is supported.")
  997. end
  998. local offset, linesize = 0x36, math.ceil((width * 3) / 4) * 4
  999.  
  1000. local surf = surface.create(width, height)
  1001. local buffer = surf.buffer
  1002. for j = 0, height - 1 do
  1003. for i = 0, width - 1 do
  1004. buffer[(j * width + i) * 3 + 1] = data:byte((height - j - 1) * linesize + i * 3 + offset + 3) / 255
  1005. buffer[(j * width + i) * 3 + 2] = data:byte((height - j - 1) * linesize + i * 3 + offset + 2) / 255
  1006. buffer[(j * width + i) * 3 + 3] = data:byte((height - j - 1) * linesize + i * 3 + offset + 1) / 255
  1007. end
  1008. end
  1009. return surf
  1010.  
  1011. elseif data:find("\30") then
  1012. -- NFT format
  1013. local width, height, lwidth = 0, 1, 0
  1014. for i = 1, #data do
  1015. if data:byte(i) == 10 then -- newline
  1016. height = height + 1
  1017. if lwidth > width then
  1018. width = lwidth
  1019. end
  1020. lwidth = 0
  1021. elseif data:byte(i) == 30 or data:byte(i) == 31 then -- color control
  1022. lwidth = lwidth - 1
  1023. elseif data:byte(i) ~= 13 then -- not carriage return
  1024. lwidth = lwidth + 1
  1025. end
  1026. end
  1027. if data:byte(#data) == 10 then
  1028. height = height - 1
  1029. end
  1030.  
  1031. local surf = surface.create(width, height)
  1032. local buffer = surf.buffer
  1033. local index, x, y, b, t = 1, 0, 0
  1034.  
  1035. while index <= #data do
  1036. if data:byte(index) == 10 then
  1037. x, y = 0, y + 1
  1038. elseif data:byte(index) == 30 then
  1039. index = index + 1
  1040. b = _cc_hex_to_color[data:sub(index, index)]
  1041. elseif data:byte(index) == 31 then
  1042. index = index + 1
  1043. t = _cc_hex_to_color[data:sub(index, index)]
  1044. elseif data:byte(index) ~= 13 then
  1045. buffer[(y * width + x) * 3 + 1] = b
  1046. buffer[(y * width + x) * 3 + 2] = t
  1047. if b or t then
  1048. buffer[(y * width + x) * 3 + 3] = data:sub(index, index)
  1049. elseif data:sub(index, index) ~= " " then
  1050. buffer[(y * width + x) * 3 + 3] = data:sub(index, index)
  1051. end
  1052. x = x + 1
  1053. end
  1054. index = index + 1
  1055. end
  1056.  
  1057. return surf
  1058. else
  1059. -- NFP format
  1060. local width, height, lwidth = 0, 1, 0
  1061. for i = 1, #data do
  1062. if data:byte(i) == 10 then -- newline
  1063. height = height + 1
  1064. if lwidth > width then
  1065. width = lwidth
  1066. end
  1067. lwidth = 0
  1068. elseif data:byte(i) ~= 13 then -- not carriage return
  1069. lwidth = lwidth + 1
  1070. end
  1071. end
  1072. if data:byte(#data) == 10 then
  1073. height = height - 1
  1074. end
  1075.  
  1076. local surf = surface.create(width, height)
  1077. local buffer = surf.buffer
  1078. local x, y = 0, 0
  1079. for i = 1, #data do
  1080. if data:byte(i) == 10 then
  1081. x, y = 0, y + 1
  1082. elseif data:byte(i) ~= 13 then
  1083. buffer[(y * width + x) * 3 + 1] = _cc_hex_to_color[data:sub(i, i)]
  1084. x = x + 1
  1085. end
  1086. end
  1087.  
  1088. return surf
  1089. end
  1090. end
  1091.  
  1092. function surf:save(file, format)
  1093. format = format or "nfp"
  1094. local data = { }
  1095. if format == "nfp" then
  1096. for j = 0, self.height - 1 do
  1097. for i = 0, self.width - 1 do
  1098. data[#data + 1] = _cc_color_to_hex[self.buffer[(j * self.width + i) * 3 + 1]] or " "
  1099. end
  1100. data[#data + 1] = "\n"
  1101. end
  1102.  
  1103. elseif format == "nft" then
  1104. for j = 0, self.height - 1 do
  1105. local b, t, pb, pt
  1106. for i = 0, self.width - 1 do
  1107. pb = self.buffer[(j * self.width + i) * 3 + 1]
  1108. pt = self.buffer[(j * self.width + i) * 3 + 2]
  1109. if pb ~= b then
  1110. data[#data + 1] = "\30"..(_cc_color_to_hex[pb] or " ")
  1111. b = pb
  1112. end
  1113. if pt ~= t then
  1114. data[#data + 1] = "\31"..(_cc_color_to_hex[pt] or " ")
  1115. t = pt
  1116. end
  1117. data[#data + 1] = self.buffer[(j * self.width + i) * 3 + 3] or " "
  1118. end
  1119. data[#data + 1] = "\n"
  1120. end
  1121.  
  1122. elseif format == "rif" then
  1123. data[1] = "RIF"
  1124. data[2] = string.char(math_floor(self.width / 256), self.width % 256)
  1125. data[3] = string.char(math_floor(self.height / 256), self.height % 256)
  1126. local byte, upper, c = 0, false
  1127. for j = 0, self.width - 1 do
  1128. for i = 0, self.height - 1 do
  1129. c = self.buffer[(j * self.width + i) * 3 + 1] or 0
  1130. if not upper then
  1131. byte = c * 16
  1132. else
  1133. byte = byte + c
  1134. data[#data + 1] = string.char(byte)
  1135. end
  1136. upper = not upper
  1137. end
  1138. end
  1139. if upper then
  1140. data[#data + 1] = string.char(byte)
  1141. end
  1142.  
  1143. elseif format == "bmp" then
  1144. data[1] = "BM"
  1145. data[2] = string.char(0, 0, 0, 0) -- file size, change later
  1146. data[3] = string.char(0, 0, 0, 0, 0x36, 0, 0, 0, 0x28, 0, 0, 0)
  1147. data[4] = string.char(self.width % 256, math_floor(self.width / 256), 0, 0)
  1148. data[5] = string.char(self.height % 256, math_floor(self.height / 256), 0, 0)
  1149. data[6] = string.char(1, 0, 0x18, 0, 0, 0, 0, 0)
  1150. data[7] = string.char(0, 0, 0, 0) -- pixel data size, change later
  1151. data[8] = string.char(0x13, 0x0B, 0, 0, 0x13, 0x0B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
  1152.  
  1153. local padchars = math.ceil((self.width * 3) / 4) * 4 - self.width * 3
  1154. for j = 0, self.height - 1 do
  1155. for i = 0, self.width - 1 do
  1156. data[#data + 1] = string.char((self.buffer[(j * self.width + i) * 3 + 1] or 0) * 255)
  1157. data[#data + 1] = string.char((self.buffer[(j * self.width + i) * 3 + 2] or 0) * 255)
  1158. data[#data + 1] = string.char((self.buffer[(j * self.width + i) * 3 + 3] or 0) * 255)
  1159. end
  1160. data[#data + 1] = ("\0"):rep(padchars)
  1161. end
  1162. local size = #table_concat(data)
  1163. data[2] = string.char(size % 256, math_floor(size / 256) % 256, math_floor(size / 65536), 0)
  1164. size = size - 54
  1165. data[7] = string.char(size % 256, math_floor(size / 256) % 256, math_floor(size / 65536), 0)
  1166.  
  1167. else
  1168. error("format not supported")
  1169. end
  1170.  
  1171. data = table_concat(data)
  1172. if file then
  1173. local handle = io.open(file, "wb")
  1174. for i = 1, #data do
  1175. handle:write(data:byte(i))
  1176. end
  1177. handle:close()
  1178. end
  1179. return data
  1180. end
  1181. function surf:drawLine(x1, y1, x2, y2, b, t, c)
  1182. if x1 == x2 then
  1183. x1, y1, x2, y2 = x1 + self.ox, y1 + self.oy, x2 + self.ox, y2 + self.oy
  1184. if x1 < self.cx or x1 >= self.cx + self.cwidth then return end
  1185. if y2 < y1 then
  1186. local temp = y1
  1187. y1 = y2
  1188. y2 = temp
  1189. end
  1190. if y1 < self.cy then y1 = self.cy end
  1191. if y2 >= self.cy + self.cheight then y2 = self.cy + self.cheight - 1 end
  1192. if b or self.overwrite then
  1193. for j = y1, y2 do
  1194. self.buffer[(j * self.width + x1) * 3 + 1] = b
  1195. end
  1196. end
  1197. if t or self.overwrite then
  1198. for j = y1, y2 do
  1199. self.buffer[(j * self.width + x1) * 3 + 2] = t
  1200. end
  1201. end
  1202. if c or self.overwrite then
  1203. for j = y1, y2 do
  1204. self.buffer[(j * self.width + x1) * 3 + 3] = c
  1205. end
  1206. end
  1207. elseif y1 == y2 then
  1208. x1, y1, x2, y2 = x1 + self.ox, y1 + self.oy, x2 + self.ox, y2 + self.oy
  1209. if y1 < self.cy or y1 >= self.cy + self.cheight then return end
  1210. if x2 < x1 then
  1211. local temp = x1
  1212. x1 = x2
  1213. x2 = temp
  1214. end
  1215. if x1 < self.cx then x1 = self.cx end
  1216. if x2 >= self.cx + self.cwidth then x2 = self.cx + self.cwidth - 1 end
  1217. if b or self.overwrite then
  1218. for i = x1, x2 do
  1219. self.buffer[(y1 * self.width + i) * 3 + 1] = b
  1220. end
  1221. end
  1222. if t or self.overwrite then
  1223. for i = x1, x2 do
  1224. self.buffer[(y1 * self.width + i) * 3 + 2] = t
  1225. end
  1226. end
  1227. if c or self.overwrite then
  1228. for i = x1, x2 do
  1229. self.buffer[(y1 * self.width + i) * 3 + 3] = c
  1230. end
  1231. end
  1232. else
  1233. local delta_x = x2 - x1
  1234. local ix = delta_x > 0 and 1 or -1
  1235. delta_x = 2 * math.abs(delta_x)
  1236. local delta_y = y2 - y1
  1237. local iy = delta_y > 0 and 1 or -1
  1238. delta_y = 2 * math.abs(delta_y)
  1239. self:drawPixel(x1, y1, b, t, c)
  1240. if delta_x >= delta_y then
  1241. local error = delta_y - delta_x / 2
  1242. while x1 ~= x2 do
  1243. if (error >= 0) and ((error ~= 0) or (ix > 0)) then
  1244. error = error - delta_x
  1245. y1 = y1 + iy
  1246. end
  1247. error = error + delta_y
  1248. x1 = x1 + ix
  1249. self:drawPixel(x1, y1, b, t, c)
  1250. end
  1251. else
  1252. local error = delta_x - delta_y / 2
  1253. while y1 ~= y2 do
  1254. if (error >= 0) and ((error ~= 0) or (iy > 0)) then
  1255. error = error - delta_y
  1256. x1 = x1 + ix
  1257. end
  1258. error = error + delta_x
  1259. y1 = y1 + iy
  1260. self:drawPixel(x1, y1, b, t, c)
  1261. end
  1262. end
  1263. end
  1264. end
  1265.  
  1266. function surf:drawRect(x, y, width, height, b, t, c)
  1267. self:drawLine(x, y, x + width - 1, y, b, t, c)
  1268. self:drawLine(x, y, x, y + height - 1, b, t, c)
  1269. self:drawLine(x + width - 1, y, x + width - 1, y + height - 1, b, t, c)
  1270. self:drawLine(x, y + height - 1, x + width - 1, y + height - 1, b, t, c)
  1271. end
  1272.  
  1273. function surf:fillRect(x, y, width, height, b, t, c)
  1274. x, y, width, height = clipRect(x + self.ox, y + self.oy, width, height, self.cx, self.cy, self.cwidth, self.cheight)
  1275.  
  1276. if b or self.overwrite then
  1277. for j = 0, height - 1 do
  1278. for i = 0, width - 1 do
  1279. self.buffer[((j + y) * self.width + i + x) * 3 + 1] = b
  1280. end
  1281. end
  1282. end
  1283. if t or self.overwrite then
  1284. for j = 0, height - 1 do
  1285. for i = 0, width - 1 do
  1286. self.buffer[((j + y) * self.width + i + x) * 3 + 2] = t
  1287. end
  1288. end
  1289. end
  1290. if c or self.overwrite then
  1291. for j = 0, height - 1 do
  1292. for i = 0, width - 1 do
  1293. self.buffer[((j + y) * self.width + i + x) * 3 + 3] = c
  1294. end
  1295. end
  1296. end
  1297. end
  1298.  
  1299. function surf:drawTriangle(x1, y1, x2, y2, x3, y3, b, t, c)
  1300. self:drawLine(x1, y1, x2, y2, b, t, c)
  1301. self:drawLine(x2, y2, x3, y3, b, t, c)
  1302. self:drawLine(x3, y3, x1, y1, b, t, c)
  1303. end
  1304.  
  1305. function surf:fillTriangle(x1, y1, x2, y2, x3, y3, b, t, c)
  1306. if y1 > y2 then
  1307. local tempx, tempy = x1, y1
  1308. x1, y1 = x2, y2
  1309. x2, y2 = tempx, tempy
  1310. end
  1311. if y1 > y3 then
  1312. local tempx, tempy = x1, y1
  1313. x1, y1 = x3, y3
  1314. x3, y3 = tempx, tempy
  1315. end
  1316. if y2 > y3 then
  1317. local tempx, tempy = x2, y2
  1318. x2, y2 = x3, y3
  1319. x3, y3 = tempx, tempy
  1320. end
  1321. if y1 == y2 and x1 > x2 then
  1322. local temp = x1
  1323. x1 = x2
  1324. x2 = temp
  1325. end
  1326. if y2 == y3 and x2 > x3 then
  1327. local temp = x2
  1328. x2 = x3
  1329. x3 = temp
  1330. end
  1331.  
  1332. local x4, y4
  1333. if x1 <= x2 then
  1334. x4 = x1 + (y2 - y1) / (y3 - y1) * (x3 - x1)
  1335. y4 = y2
  1336. local tempx, tempy = x2, y2
  1337. x2, y2 = x4, y4
  1338. x4, y4 = tempx, tempy
  1339. else
  1340. x4 = x1 + (y2 - y1) / (y3 - y1) * (x3 - x1)
  1341. y4 = y2
  1342. end
  1343.  
  1344. local finvslope1 = (x2 - x1) / (y2 - y1)
  1345. local finvslope2 = (x4 - x1) / (y4 - y1)
  1346. local linvslope1 = (x3 - x2) / (y3 - y2)
  1347. local linvslope2 = (x3 - x4) / (y3 - y4)
  1348.  
  1349. local xstart, xend, dxstart, dxend
  1350. for y = math.ceil(y1 + 0.5) - 0.5, math.floor(y3 - 0.5) + 0.5, 1 do
  1351. if y <= y2 then -- first half
  1352. xstart = x1 + finvslope1 * (y - y1)
  1353. xend = x1 + finvslope2 * (y - y1)
  1354. else -- second half
  1355. xstart = x3 - linvslope1 * (y3 - y)
  1356. xend = x3 - linvslope2 * (y3 - y)
  1357. end
  1358.  
  1359. dxstart, dxend = math.ceil(xstart - 0.5), math.floor(xend - 0.5)
  1360. if dxstart <= dxend then
  1361. self:drawLine(dxstart, y - 0.5, dxend, y - 0.5, b, t, c)
  1362. end
  1363. end
  1364. end
  1365.  
  1366. function surf:drawEllipse(x, y, width, height, b, t, c)
  1367. for i = 0, _eprc - 1 do
  1368. self:drawLine(math_floor(x + _ecos[i + 1] * (width - 1) + 0.5), math_floor(y + _esin[i + 1] * (height - 1) + 0.5), math_floor(x + _ecos[(i + 1) % _eprc + 1] * (width - 1) + 0.5), math_floor(y + _esin[(i + 1) % _eprc + 1] * (height - 1) + 0.5), b, t, c)
  1369. end
  1370. end
  1371.  
  1372. function surf:fillEllipse(x, y, width, height, b, t, c)
  1373. x, y = x + self.ox, y + self.oy
  1374.  
  1375. for j = 0, height - 1 do
  1376. for i = 0, width - 1 do
  1377. if ((i + 0.5) / width * 2 - 1) ^ 2 + ((j + 0.5) / height * 2 - 1) ^ 2 <= 1 then
  1378. if b or self.overwrite then
  1379. self.buffer[((j + y) * self.width + i + x) * 3 + 1] = b
  1380. end
  1381. if t or self.overwrite then
  1382. self.buffer[((j + y) * self.width + i + x) * 3 + 2] = t
  1383. end
  1384. if c or self.overwrite then
  1385. self.buffer[((j + y) * self.width + i + x) * 3 + 3] = c
  1386. end
  1387. end
  1388. end
  1389. end
  1390. end
  1391.  
  1392. function surf:drawArc(x, y, width, height, fromangle, toangle, b, t, c)
  1393. if fromangle > toangle then
  1394. local temp = fromangle
  1395. fromangle = toangle
  1396. temp = toangle
  1397. end
  1398. fromangle = math_floor(fromangle / math.pi / 2 * _eprc + 0.5)
  1399. toangle = math_floor(toangle / math.pi / 2 * _eprc + 0.5) - 1
  1400.  
  1401. for j = fromangle, toangle do
  1402. local i = j % _eprc
  1403. self:drawLine(math_floor(x + _ecos[i + 1] * (width - 1) + 0.5), math_floor(y + _esin[i + 1] * (height - 1) + 0.5), math_floor(x + _ecos[(i + 1) % _eprc + 1] * (width - 1) + 0.5), math_floor(y + _esin[(i + 1) % _eprc + 1] * (height - 1) + 0.5), b, t, c)
  1404. end
  1405. end
  1406.  
  1407. function surf:fillArc(x, y, width, height, fromangle, toangle, b, t, c)
  1408. x, y = x + self.ox, y + self.oy
  1409.  
  1410. if fromangle > toangle then
  1411. local temp = fromangle
  1412. fromangle = toangle
  1413. temp = toangle
  1414. end
  1415. local diff = toangle - fromangle
  1416. fromangle = fromangle % (math.pi * 2)
  1417.  
  1418. local fx, fy, dir
  1419. for j = 0, height - 1 do
  1420. for i = 0, width - 1 do
  1421. fx, fy = (i + 0.5) / width * 2 - 1, (j + 0.5) / height * 2 - 1
  1422. dir = math_atan2(-fy, fx) % (math.pi * 2)
  1423. if fx ^ 2 + fy ^ 2 <= 1 and ((dir >= fromangle and dir - fromangle <= diff) or (dir <= (fromangle + diff) % (math.pi * 2))) then
  1424. if b or self.overwrite then
  1425. self.buffer[((j + y) * self.width + i + x) * 3 + 1] = b
  1426. end
  1427. if t or self.overwrite then
  1428. self.buffer[((j + y) * self.width + i + x) * 3 + 2] = t
  1429. end
  1430. if c or self.overwrite then
  1431. self.buffer[((j + y) * self.width + i + x) * 3 + 3] = c
  1432. end
  1433. end
  1434. end
  1435. end
  1436. end
  1437. function surf:drawSurface(surf2, x, y, width, height, sx, sy, swidth, sheight)
  1438. x, y, width, height, sx, sy, swidth, sheight = x + self.ox, y + self.oy, width or surf2.width, height or surf2.height, sx or 0, sy or 0, swidth or surf2.width, sheight or surf2.height
  1439.  
  1440. if width == swidth and height == sheight then
  1441. local nx, ny
  1442. nx, ny, width, height = clipRect(x, y, width, height, self.cx, self.cy, self.cwidth, self.cheight)
  1443. swidth, sheight = width, height
  1444. if nx > x then
  1445. sx = sx + nx - x
  1446. x = nx
  1447. end
  1448. if ny > y then
  1449. sy = sy + ny - y
  1450. y = ny
  1451. end
  1452. nx, ny, swidth, sheight = clipRect(sx, sy, swidth, sheight, 0, 0, surf2.width, surf2.height)
  1453. width, height = swidth, sheight
  1454. if nx > sx then
  1455. x = x + nx - sx
  1456. sx = nx
  1457. end
  1458. if ny > sy then
  1459. y = y + ny - sy
  1460. sy = ny
  1461. end
  1462.  
  1463. local b, t, c
  1464. for j = 0, height - 1 do
  1465. for i = 0, width - 1 do
  1466. b = surf2.buffer[((j + sy) * surf2.width + i + sx) * 3 + 1]
  1467. t = surf2.buffer[((j + sy) * surf2.width + i + sx) * 3 + 2]
  1468. c = surf2.buffer[((j + sy) * surf2.width + i + sx) * 3 + 3]
  1469. if b or self.overwrite then
  1470. self.buffer[((j + y) * self.width + i + x) * 3 + 1] = b
  1471. end
  1472. if t or self.overwrite then
  1473. self.buffer[((j + y) * self.width + i + x) * 3 + 2] = t
  1474. end
  1475. if c or self.overwrite then
  1476. self.buffer[((j + y) * self.width + i + x) * 3 + 3] = c
  1477. end
  1478. end
  1479. end
  1480. else
  1481. local hmirror, vmirror = false, false
  1482. if width < 0 then
  1483. hmirror = true
  1484. x = x + width
  1485. end
  1486. if height < 0 then
  1487. vmirror = true
  1488. y = y + height
  1489. end
  1490. if swidth < 0 then
  1491. hmirror = not hmirror
  1492. sx = sx + swidth
  1493. end
  1494. if sheight < 0 then
  1495. vmirror = not vmirror
  1496. sy = sy + sheight
  1497. end
  1498. width, height, swidth, sheight = math.abs(width), math.abs(height), math.abs(swidth), math.abs(sheight)
  1499.  
  1500. local xscale, yscale, px, py, ssx, ssy, b, t, c = swidth / width, sheight / height
  1501. for j = 0, height - 1 do
  1502. for i = 0, width - 1 do
  1503. px, py = math_floor((i + 0.5) * xscale), math_floor((j + 0.5) * yscale)
  1504. if hmirror then
  1505. ssx = x + width - i - 1
  1506. else
  1507. ssx = i + x
  1508. end
  1509. if vmirror then
  1510. ssy = y + height - j - 1
  1511. else
  1512. ssy = j + y
  1513. end
  1514.  
  1515. if ssx >= self.cx and ssx < self.cx + self.cwidth and ssy >= self.cy and ssy < self.cy + self.cheight and px >= 0 and px < surf2.width and py >= 0 and py < surf2.height then
  1516. b = surf2.buffer[(py * surf2.width + px) * 3 + 1]
  1517. t = surf2.buffer[(py * surf2.width + px) * 3 + 2]
  1518. c = surf2.buffer[(py * surf2.width + px) * 3 + 3]
  1519. if b or self.overwrite then
  1520. self.buffer[(ssy * self.width + ssx) * 3 + 1] = b
  1521. end
  1522. if t or self.overwrite then
  1523. self.buffer[(ssy * self.width + ssx) * 3 + 2] = t
  1524. end
  1525. if c or self.overwrite then
  1526. self.buffer[(ssy * self.width + ssx) * 3 + 3] = c
  1527. end
  1528. end
  1529. end
  1530. end
  1531. end
  1532. end
  1533.  
  1534. function surf:drawSurfaceRotated(surf2, x, y, ox, oy, angle)
  1535. local sin, cos, sx, sy, px, py = math.sin(angle), math.cos(angle)
  1536. for j = math.floor(-surf2.height * 0.75), math.ceil(surf2.height * 0.75) do
  1537. for i = math.floor(-surf2.width * 0.75), math.ceil(surf2.width * 0.75) do
  1538. sx, sy, px, py = x + i, y + j, math_floor(cos * (i + 0.5) - sin * (j + 0.5) + ox), math_floor(sin * (i + 0.5) + cos * (j + 0.5) + oy)
  1539. if sx >= self.cx and sx < self.cx + self.cwidth and sy >= self.cy and sy < self.cy + self.cheight and px >= 0 and px < surf2.width and py >= 0 and py < surf2.height then
  1540. b = surf2.buffer[(py * surf2.width + px) * 3 + 1]
  1541. t = surf2.buffer[(py * surf2.width + px) * 3 + 2]
  1542. c = surf2.buffer[(py * surf2.width + px) * 3 + 3]
  1543. if b or self.overwrite then
  1544. self.buffer[(sy * self.width + sx) * 3 + 1] = b
  1545. end
  1546. if t or self.overwrite then
  1547. self.buffer[(sy * self.width + sx) * 3 + 2] = t
  1548. end
  1549. if c or self.overwrite then
  1550. self.buffer[(sy * self.width + sx) * 3 + 3] = c
  1551. end
  1552. end
  1553. end
  1554. end
  1555. end
  1556.  
  1557. function surf:drawSurfacesInterlaced(surfs, x, y, step)
  1558. x, y, step = x + self.ox, y + self.oy, step or 0
  1559. local width, height = surfs[1].width, surfs[1].height
  1560. for i = 2, #surfs do
  1561. if surfs[i].width ~= width or surfs[i].height ~= height then
  1562. error("surfaces should be the same size")
  1563. end
  1564. end
  1565.  
  1566. local sx, sy, swidth, sheight, index, b, t, c = clipRect(x, y, width, height, self.cx, self.cy, self.cwidth, self.cheight)
  1567. for j = sy, sy + sheight - 1 do
  1568. for i = sx, sx + swidth - 1 do
  1569. index = (i + j + step) % #surfs + 1
  1570. b = surfs[index].buffer[((j - sy) * surfs[index].width + i - sx) * 3 + 1]
  1571. t = surfs[index].buffer[((j - sy) * surfs[index].width + i - sx) * 3 + 2]
  1572. c = surfs[index].buffer[((j - sy) * surfs[index].width + i - sx) * 3 + 3]
  1573. if b or self.overwrite then
  1574. self.buffer[(j * self.width + i) * 3 + 1] = b
  1575. end
  1576. if t or self.overwrite then
  1577. self.buffer[(j * self.width + i) * 3 + 2] = t
  1578. end
  1579. if c or self.overwrite then
  1580. self.buffer[(j * self.width + i) * 3 + 3] = c
  1581. end
  1582. end
  1583. end
  1584. end
  1585.  
  1586. function surf:drawSurfaceSmall(surf2, x, y)
  1587. x, y = x + self.ox, y + self.oy
  1588. if surf2.width % 2 ~= 0 or surf2.height % 3 ~= 0 then
  1589. error("surface width must be a multiple of 2 and surface height a multiple of 3")
  1590. end
  1591.  
  1592. local sub, char, c1, c2, c3, c4, c5, c6 = 32768
  1593. for j = 0, surf2.height / 3 - 1 do
  1594. for i = 0, surf2.width / 2 - 1 do
  1595. if i + x >= self.cx and i + x < self.cx + self.cwidth and j + y >= self.cy and j + y < self.cy + self.cheight then
  1596. char, c1, c2, c3, c4, c5, c6 = 0,
  1597. surf2.buffer[((j * 3) * surf2.width + i * 2) * 3 + 1],
  1598. surf2.buffer[((j * 3) * surf2.width + i * 2 + 1) * 3 + 1],
  1599. surf2.buffer[((j * 3 + 1) * surf2.width + i * 2) * 3 + 1],
  1600. surf2.buffer[((j * 3 + 1) * surf2.width + i * 2 + 1) * 3 + 1],
  1601. surf2.buffer[((j * 3 + 2) * surf2.width + i * 2) * 3 + 1],
  1602. surf2.buffer[((j * 3 + 2) * surf2.width + i * 2 + 1) * 3 + 1]
  1603. if c1 ~= c6 then
  1604. sub = c1
  1605. char = 1
  1606. end
  1607. if c2 ~= c6 then
  1608. sub = c2
  1609. char = char + 2
  1610. end
  1611. if c3 ~= c6 then
  1612. sub = c3
  1613. char = char + 4
  1614. end
  1615. if c4 ~= c6 then
  1616. sub = c4
  1617. char = char + 8
  1618. end
  1619. if c5 ~= c6 then
  1620. sub = c5
  1621. char = char + 16
  1622. end
  1623. self.buffer[((j + y) * self.width + i + x) * 3 + 1] = c6
  1624. self.buffer[((j + y) * self.width + i + x) * 3 + 2] = sub
  1625. self.buffer[((j + y) * self.width + i + x) * 3 + 3] = _chars[128 + char]
  1626. end
  1627. end
  1628. end
  1629. end
  1630. function surf:flip(horizontal, vertical)
  1631. local ox, oy, nx, ny, tb, tt, tc
  1632. if horizontal then
  1633. for i = 0, math.ceil(self.cwidth / 2) - 1 do
  1634. for j = 0, self.cheight - 1 do
  1635. ox, oy, nx, ny = i + self.cx, j + self.cy, self.cx + self.cwidth - i - 1, j + self.cy
  1636. tb = self.buffer[(oy * self.width + ox) * 3 + 1]
  1637. tt = self.buffer[(oy * self.width + ox) * 3 + 2]
  1638. tc = self.buffer[(oy * self.width + ox) * 3 + 3]
  1639. self.buffer[(oy * self.width + ox) * 3 + 1] = self.buffer[(ny * self.width + nx) * 3 + 1]
  1640. self.buffer[(oy * self.width + ox) * 3 + 2] = self.buffer[(ny * self.width + nx) * 3 + 2]
  1641. self.buffer[(oy * self.width + ox) * 3 + 3] = self.buffer[(ny * self.width + nx) * 3 + 3]
  1642. self.buffer[(ny * self.width + nx) * 3 + 1] = tb
  1643. self.buffer[(ny * self.width + nx) * 3 + 2] = tt
  1644. self.buffer[(ny * self.width + nx) * 3 + 3] = tc
  1645. end
  1646. end
  1647. end
  1648. if vertical then
  1649. for j = 0, math.ceil(self.cheight / 2) - 1 do
  1650. for i = 0, self.cwidth - 1 do
  1651. ox, oy, nx, ny = i + self.cx, j + self.cy, i + self.cx, self.cy + self.cheight - j - 1
  1652. tb = self.buffer[(oy * self.width + ox) * 3 + 1]
  1653. tt = self.buffer[(oy * self.width + ox) * 3 + 2]
  1654. tc = self.buffer[(oy * self.width + ox) * 3 + 3]
  1655. self.buffer[(oy * self.width + ox) * 3 + 1] = self.buffer[(ny * self.width + nx) * 3 + 1]
  1656. self.buffer[(oy * self.width + ox) * 3 + 2] = self.buffer[(ny * self.width + nx) * 3 + 2]
  1657. self.buffer[(oy * self.width + ox) * 3 + 3] = self.buffer[(ny * self.width + nx) * 3 + 3]
  1658. self.buffer[(ny * self.width + nx) * 3 + 1] = tb
  1659. self.buffer[(ny * self.width + nx) * 3 + 2] = tt
  1660. self.buffer[(ny * self.width + nx) * 3 + 3] = tc
  1661. end
  1662. end
  1663. end
  1664. end
  1665.  
  1666. function surf:shift(x, y, b, t, c)
  1667. local hdir, vdir = x < 0, y < 0
  1668. local xstart, xend = self.cx, self.cx + self.cwidth - 1
  1669. local ystart, yend = self.cy, self.cy + self.cheight - 1
  1670. local nx, ny
  1671. for j = vdir and ystart or yend, vdir and yend or ystart, vdir and 1 or -1 do
  1672. for i = hdir and xstart or xend, hdir and xend or xstart, hdir and 1 or -1 do
  1673. nx, ny = i - x, j - y
  1674. if nx >= 0 and nx < self.width and ny >= 0 and ny < self.height then
  1675. self.buffer[(j * self.width + i) * 3 + 1] = self.buffer[(ny * self.width + nx) * 3 + 1]
  1676. self.buffer[(j * self.width + i) * 3 + 2] = self.buffer[(ny * self.width + nx) * 3 + 2]
  1677. self.buffer[(j * self.width + i) * 3 + 3] = self.buffer[(ny * self.width + nx) * 3 + 3]
  1678. else
  1679. self.buffer[(j * self.width + i) * 3 + 1] = b
  1680. self.buffer[(j * self.width + i) * 3 + 2] = t
  1681. self.buffer[(j * self.width + i) * 3 + 3] = c
  1682. end
  1683. end
  1684. end
  1685. end
  1686.  
  1687. function surf:map(colors)
  1688. local c
  1689. for j = self.cy, self.cy + self.cheight - 1 do
  1690. for i = self.cx, self.cx + self.cwidth - 1 do
  1691. c = colors[self.buffer[(j * self.width + i) * 3 + 1]]
  1692. if c or self.overwrite then
  1693. self.buffer[(j * self.width + i) * 3 + 1] = c
  1694. end
  1695. end
  1696. end
  1697. end
  1698. surface.palette = { }
  1699. surface.palette.cc = {[1]="F0F0F0",[2]="F2B233",[4]="E57FD8",[8]="99B2F2",[16]="DEDE6C",[32]="7FCC19",[64]="F2B2CC",[128]="4C4C4C",[256]="999999",[512]="4C99B2",[1024]="B266E5",[2048]="3366CC",[4096]="7F664C",[8192]="57A64E",[16384]="CC4C4C",[32768]="191919"}
  1700. surface.palette.riko4 = {"181818","1D2B52","7E2553","008651","AB5136","5F564F","7D7F82","FF004C","FFA300","FFF023","00E755","29ADFF","82769C","FF77A9","FECCA9","ECECEC"}
  1701.  
  1702. local function setPalette(palette)
  1703. if palette == _palette then return end
  1704. _palette = palette
  1705. _rgbpal, _palr, _palg, _palb = { }, { }, { }, { }
  1706.  
  1707. local indices = { }
  1708. for k, v in pairs(_palette) do
  1709. if type(v) == "string" then
  1710. _palr[k] = tonumber(v:sub(1, 2), 16) / 255
  1711. _palg[k] = tonumber(v:sub(3, 4), 16) / 255
  1712. _palb[k] = tonumber(v:sub(5, 6), 16) / 255
  1713. elseif type(v) == "number" then
  1714. _palr[k] = math.floor(v / 65536) / 255
  1715. _palg[k] = (math.floor(v / 256) % 256) / 255
  1716. _palb[k] = (v % 256) / 255
  1717. end
  1718. indices[#indices + 1] = k
  1719. end
  1720.  
  1721. local pr, pg, pb, dist, d, id
  1722. for i = 0, _steps - 1 do
  1723. for j = 0, _steps - 1 do
  1724. for k = 0, _steps - 1 do
  1725. pr = (i + 0.5) / _steps
  1726. pg = (j + 0.5) / _steps
  1727. pb = (k + 0.5) / _steps
  1728.  
  1729. dist = 1e10
  1730. for l = 1, #indices do
  1731. d = (pr - _palr[indices[l]]) ^ 2 + (pg - _palg[indices[l]]) ^ 2 + (pb - _palb[indices[l]]) ^ 2
  1732. if d < dist then
  1733. dist = d
  1734. id = l
  1735. end
  1736. end
  1737. _rgbpal[i * _steps * _steps + j * _steps + k + 1] = indices[id]
  1738. end
  1739. end
  1740. end
  1741. end
  1742.  
  1743.  
  1744.  
  1745. function surf:toRGB(palette)
  1746. setPalette(palette)
  1747. local c
  1748. for j = 0, self.height - 1 do
  1749. for i = 0, self.width - 1 do
  1750. c = self.buffer[(j * self.width + i) * 3 + 1]
  1751. self.buffer[(j * self.width + i) * 3 + 1] = _palr[c]
  1752. self.buffer[(j * self.width + i) * 3 + 2] = _palg[c]
  1753. self.buffer[(j * self.width + i) * 3 + 3] = _palb[c]
  1754. end
  1755. end
  1756. end
  1757.  
  1758. function surf:toPalette(palette, dither)
  1759. setPalette(palette)
  1760. local scale, r, g, b, nr, ng, nb, c, dr, dg, db = _steps - 1
  1761. for j = 0, self.height - 1 do
  1762. for i = 0, self.width - 1 do
  1763. r = self.buffer[(j * self.width + i) * 3 + 1]
  1764. g = self.buffer[(j * self.width + i) * 3 + 2]
  1765. b = self.buffer[(j * self.width + i) * 3 + 3]
  1766. r = (r > 1) and 1 or r
  1767. r = (r < 0) and 0 or r
  1768. g = (g > 1) and 1 or g
  1769. g = (g < 0) and 0 or g
  1770. b = (b > 1) and 1 or b
  1771. b = (b < 0) and 0 or b
  1772.  
  1773. nr = (r == 1) and scale or math_floor(r * _steps)
  1774. ng = (g == 1) and scale or math_floor(g * _steps)
  1775. nb = (b == 1) and scale or math_floor(b * _steps)
  1776. c = _rgbpal[nr * _steps * _steps + ng * _steps + nb + 1]
  1777. if dither then
  1778. dr = (r - _palr[c]) / 16
  1779. dg = (g - _palg[c]) / 16
  1780. db = (b - _palb[c]) / 16
  1781.  
  1782. if i < self.width - 1 then
  1783. self.buffer[(j * self.width + i + 1) * 3 + 1] = self.buffer[(j * self.width + i + 1) * 3 + 1] + dr * 7
  1784. self.buffer[(j * self.width + i + 1) * 3 + 2] = self.buffer[(j * self.width + i + 1) * 3 + 2] + dg * 7
  1785. self.buffer[(j * self.width + i + 1) * 3 + 3] = self.buffer[(j * self.width + i + 1) * 3 + 3] + db * 7
  1786. end
  1787. if j < self.height - 1 then
  1788. if i > 0 then
  1789. self.buffer[((j + 1) * self.width + i - 1) * 3 + 1] = self.buffer[((j + 1) * self.width + i - 1) * 3 + 1] + dr * 3
  1790. self.buffer[((j + 1) * self.width + i - 1) * 3 + 2] = self.buffer[((j + 1) * self.width + i - 1) * 3 + 2] + dg * 3
  1791. self.buffer[((j + 1) * self.width + i - 1) * 3 + 3] = self.buffer[((j + 1) * self.width + i - 1) * 3 + 3] + db * 3
  1792. end
  1793. self.buffer[((j + 1) * self.width + i) * 3 + 1] = self.buffer[((j + 1) * self.width + i) * 3 + 1] + dr * 5
  1794. self.buffer[((j + 1) * self.width + i) * 3 + 2] = self.buffer[((j + 1) * self.width + i) * 3 + 2] + dg * 5
  1795. self.buffer[((j + 1) * self.width + i) * 3 + 3] = self.buffer[((j + 1) * self.width + i) * 3 + 3] + db * 5
  1796. if i < self.width - 1 then
  1797. self.buffer[((j + 1) * self.width + i + 1) * 3 + 1] = self.buffer[((j + 1) * self.width + i + 1) * 3 + 1] + dr * 1
  1798. self.buffer[((j + 1) * self.width + i + 1) * 3 + 2] = self.buffer[((j + 1) * self.width + i + 1) * 3 + 2] + dg * 1
  1799. self.buffer[((j + 1) * self.width + i + 1) * 3 + 3] = self.buffer[((j + 1) * self.width + i + 1) * 3 + 3] + db * 1
  1800. end
  1801. end
  1802. end
  1803. self.buffer[(j * self.width + i) * 3 + 1] = c
  1804. self.buffer[(j * self.width + i) * 3 + 2] = nil
  1805. self.buffer[(j * self.width + i) * 3 + 3] = nil
  1806. end
  1807. end
  1808. end
  1809. function surface.loadFont(surf)
  1810. local font = {width = surf.width, height = surf.height - 1}
  1811. font.buffer = { }
  1812. font.indices = {0}
  1813. font.widths = { }
  1814.  
  1815. local startc, hitc, curc = surf.buffer[((surf.height - 1) * surf.width) * 3 + 1]
  1816. for i = 0, surf.width - 1 do
  1817. curc = surf.buffer[((surf.height - 1) * surf.width + i) * 3 + 1]
  1818. if curc ~= startc then
  1819. hitc = curc
  1820. break
  1821. end
  1822. end
  1823.  
  1824. for j = 0, surf.height - 2 do
  1825. for i = 0, surf.width - 1 do
  1826. font.buffer[j * font.width + i + 1] = surf.buffer[(j * surf.width + i) * 3 + 1] == hitc
  1827. end
  1828. end
  1829.  
  1830. local curchar = 1
  1831. for i = 0, surf.width - 1 do
  1832. if surf.buffer[((surf.height - 1) * surf.width + i) * 3 + 1] == hitc then
  1833. font.widths[curchar] = i - font.indices[curchar]
  1834. curchar = curchar + 1
  1835. font.indices[curchar] = i + 1
  1836. end
  1837. end
  1838. font.widths[curchar] = font.width - font.indices[curchar] + 1
  1839.  
  1840. return font
  1841. end
  1842.  
  1843. function surface.getTextSize(str, font)
  1844. local cx, cy, maxx = 0, 0, 0
  1845. local ox, char = cx
  1846.  
  1847. for i = 1, #str do
  1848. char = str:byte(i) - 31
  1849.  
  1850. if char + 31 == 10 then -- newline
  1851. cx = ox
  1852. cy = cy + font.height + 1
  1853. elseif font.indices[char] then
  1854. cx = cx + font.widths[char] + 1
  1855. else
  1856. cx = cx + font.widths[1]
  1857. end
  1858. if cx > maxx then
  1859. maxx = cx
  1860. end
  1861. end
  1862.  
  1863. return maxx - 1, cy + font.height
  1864. end
  1865.  
  1866. function surf:drawText(str, x, y, font, b, t, c)
  1867. local cx, cy = x + self.ox, y + self.oy
  1868. local ox, char, idx = cx
  1869.  
  1870. for i = 1, #str do
  1871. char = str:byte(i) - 31
  1872.  
  1873. if char + 31 == 10 then -- newline
  1874. cx = ox
  1875. cy = cy + font.height + 1
  1876. elseif font.indices[char] then
  1877. for i = 0, font.widths[char] - 1 do
  1878. for j = 0, font.height - 1 do
  1879. x, y = cx + i, cy + j
  1880. if font.buffer[j * font.width + i + font.indices[char] + 1] then
  1881. if x >= self.cx and x < self.cx + self.cwidth and y >= self.cy and y < self.cy + self.cheight then
  1882. idx = (y * self.width + x) * 3
  1883. if b or self.overwrite then
  1884. self.buffer[idx + 1] = b
  1885. end
  1886. if t or self.overwrite then
  1887. self.buffer[idx + 2] = t
  1888. end
  1889. if c or self.overwrite then
  1890. self.buffer[idx + 3] = c
  1891. end
  1892. end
  1893. end
  1894. end
  1895. end
  1896. cx = cx + font.widths[char] + 1
  1897. else
  1898. cx = cx + font.widths[1]
  1899. end
  1900. end
  1901. end
  1902. end
  1903.  
  1904.  
  1905.  
  1906.  
  1907.  
  1908. local sin, cos = math.sin, math.cos
  1909. local halfpi = math.pi / 2
  1910.  
  1911. Easing = class.new_enum "Easing" {
  1912. linear = function( u, d, t )
  1913. return u + d * t
  1914. end;
  1915.  
  1916. smooth = function( u, d, t )
  1917. return u + d * ( 3 * t * t - 2 * t * t * t )
  1918. end;
  1919.  
  1920. exit = function( u, d, t )
  1921. return -d * cos(t * halfpi) + d + u
  1922. end;
  1923.  
  1924. entrance = function( u, d, t )
  1925. return u + d * sin(t * halfpi)
  1926. end;
  1927.  
  1928. -- TODO: probably should add in all the default ones but why are they required?
  1929. }
  1930.  
  1931.  
  1932.  
  1933.  
  1934.  
  1935. local thrown
  1936.  
  1937. local function handler( t )
  1938. for i = 1, #t do
  1939. if t[i].catch == thrown.name or t[i].default or t[i].catch == thrown.class then
  1940. return t[i].handler( thrown )
  1941. end
  1942. end
  1943. return Exception.throw( thrown )
  1944. end
  1945.  
  1946. Exception = class.new( "Exception", nil, nil ) {
  1947. name = "undefined";
  1948. data = "undefined";
  1949. trace = {};
  1950. }
  1951.  
  1952. function Exception:Exception( name, data, level )
  1953. self.name = name
  1954. self.data = data
  1955. self.trace = {}
  1956.  
  1957. level = ( level or 1 ) + 2
  1958.  
  1959. if level > 2 then
  1960. for i = 1, 5 do
  1961. local src = select( 2, pcall( error, "", level + i ) ):gsub( ": $", "" )
  1962.  
  1963. if src == "pcall" or src == "" then
  1964. break
  1965. else
  1966. self.trace[i] = src
  1967. end
  1968. end
  1969. end
  1970. end
  1971.  
  1972. function Exception:get_traceback( initial, delimiter )
  1973. initial = initial or ""
  1974. delimiter = delimiter or "\n"
  1975.  
  1976. parameters.check( 2, "initial", "string", initial, "delimiter", "string", delimiter )
  1977.  
  1978. if #self.trace == 0 then return "" end
  1979.  
  1980. return initial .. table.concat( self.trace, delimiter )
  1981. end
  1982.  
  1983. function Exception:get_data()
  1984. if type( self.data ) == "string" or class.is_class( self.data ) or class.is_instance( self.data ) then
  1985. return tostring( self.data )
  1986. else
  1987. return textutils.serialize( self.data )
  1988. end
  1989. end
  1990.  
  1991. function Exception:get_data_and_traceback( indent )
  1992. parameters.check( 1, "indent", "number", indent or 1 )
  1993.  
  1994. return self:get_data() .. self:get_traceback( "\n" .. (" "):rep( indent or 1 ) .. "in ", "\n" .. (" "):rep( indent or 1 ) .. "in " )
  1995. end
  1996.  
  1997. function Exception:tostring()
  1998. return tostring( self.name ) .. " exception:\n " .. self:get_data_and_traceback( 4 )
  1999. end
  2000.  
  2001. function Exception.thrown()
  2002. return thrown
  2003. end
  2004.  
  2005. function Exception.throw( e, data, level )
  2006. if class.is_class( e ) then
  2007. e = e( data, ( level or 1 ) + 1 )
  2008. elseif type( e ) == "string" then
  2009. e = Exception( e, data, ( level or 1 ) + 1 )
  2010. elseif not class.type_of( e, Exception ) then
  2011. return Exception.throw( "IncorrectParameterException", "expected class, string, or Exception e, got " .. class.type( e ) )
  2012. end
  2013. thrown = e
  2014. error( "SHEETS_EXCEPTION\nPut code in a try block to catch the exception.", 0 )
  2015. end
  2016.  
  2017. function Exception.try( func )
  2018. local ok, err = pcall( func )
  2019.  
  2020. if not ok and err == "SHEETS_EXCEPTION\nPut code in a try block to catch the exception." then
  2021. return handler
  2022. end
  2023.  
  2024. return error( err, 0 )
  2025. end
  2026.  
  2027. function Exception.catch( etype )
  2028. return function( handler )
  2029. return { catch = etype, handler = handler }
  2030. end
  2031. end
  2032.  
  2033. function Exception.default( handler )
  2034. return { default = true, handler = handler }
  2035. end
  2036.  
  2037.  
  2038.  
  2039.  
  2040. IncorrectParameterException = class.new( "IncorrectParameterException", Exception, nil ) {
  2041.  
  2042. }
  2043.  
  2044. function IncorrectParameterException:IncorrectParameterException( data, level )
  2045. return self:Exception( "IncorrectParameterException", data, level )
  2046. end
  2047.  
  2048.  
  2049.  
  2050.  
  2051. IncorrectConstructorException = class.new( "IncorrectConstructorException", Exception, nil ) {
  2052.  
  2053. }
  2054.  
  2055. function IncorrectConstructorException:IncorrectConstructorException( data, level )
  2056. return self:Exception( "IncorrectConstructorException", data, level )
  2057. end
  2058.  
  2059.  
  2060.  
  2061.  
  2062. ResourceLoadException = class.new( "ResourceLoadException", Exception, nil ) {
  2063.  
  2064. }
  2065.  
  2066. function ResourceLoadException:ResourceLoadException( data, level )
  2067. return self:Exception( "ResourceLoadException", data, level )
  2068. end
  2069.  
  2070.  
  2071.  
  2072.  
  2073. ThreadRuntimeException = class.new( "ThreadRuntimeException", Exception, nil ) {
  2074.  
  2075. }
  2076.  
  2077. function ThreadRuntimeException:ThreadRuntimeException( data, level )
  2078. return self:Exception( "ThreadRuntimeException", data, level )
  2079. end
  2080.  
  2081.  
  2082.  
  2083.  
  2084.  
  2085. ICollatedChildren = class.new_interface( "ICollatedChildren", nil ) {
  2086. collated_children = {}
  2087. }
  2088.  
  2089. function ICollatedChildren:ICollatedChildren()
  2090. self.collated_children = {}
  2091. end
  2092.  
  2093. function ICollatedChildren:update_collated( mode, child, data )
  2094. local collated = self.collated_children
  2095.  
  2096. if mode == "child-added" then
  2097. if data == self then
  2098. if child:implements( ICollatedChildren ) then
  2099. for i = 1, #child.collated_children do
  2100. collated[#collated + 1] = child.collated_children[i]
  2101. end
  2102. end
  2103.  
  2104. collated[#collated + 1] = child
  2105. else
  2106. for i = #collated, 1, -1 do
  2107. if collated[i] == data then
  2108. if child:implements( ICollatedChildren ) then
  2109. i = i - 1 -- so that i + n starts with just i
  2110.  
  2111. for n = 1, #child.collated_children do
  2112. table.insert( collated, i + n, child.collated_children[n] )
  2113. end
  2114.  
  2115. table.insert( collated, i + #child.collated_children + 1, child )
  2116. else
  2117. table.insert( collated, i, child )
  2118. end
  2119. end
  2120. end
  2121. end
  2122.  
  2123. if self.parent then
  2124. self.parent:update_collated( "child-added", child, data )
  2125. end
  2126. elseif mode == "child-removed" then
  2127. local open, close = child:implements( ICollatedChildren ) and child.collated_children[1] or child, child
  2128. local removing = false
  2129.  
  2130. for i = #collated, 1, -1 do
  2131. if collated[i] == close then removing = true end
  2132. local brk = collated[i] == open
  2133. if removing then table.remove( collated, i ) end
  2134. if brk then break end
  2135. end
  2136.  
  2137. if self.parent then
  2138. self.parent:update_collated( "child-removed", child )
  2139. end
  2140. end
  2141.  
  2142. if self.query_tracker then
  2143. self.query_tracker:update( mode, child )
  2144. end
  2145. end
  2146.  
  2147.  
  2148.  
  2149.  
  2150. IColoured = class.new_interface( "IColoured", nil ) {
  2151. colour = nil;
  2152. }
  2153.  
  2154. function IColoured:IColoured()
  2155. self.values:add( "colour", 1 )
  2156. end
  2157.  
  2158.  
  2159.  
  2160.  
  2161. local setf, addtag, remtag, query_raw
  2162.  
  2163. IQueryable = class.new_interface( "IQueryable", ICollatedChildren ) {
  2164. query_tracker = nil;
  2165. }
  2166.  
  2167. function IQueryable:IQueryable()
  2168. self.query_tracker = QueryTracker( self )
  2169. end
  2170.  
  2171. function IQueryable:iquery( query )
  2172. local results = query_raw( self, query, nil, false, false )
  2173. local i = 0
  2174.  
  2175. return function()
  2176. i = i + 1
  2177. return results[i], i
  2178. end
  2179. end
  2180.  
  2181. function IQueryable:query( query )
  2182. return query_raw( self, query, nil, false, false )
  2183. end
  2184.  
  2185. function IQueryable:query_tracked( query )
  2186. return query_raw( self, query, nil, true, false )
  2187. end
  2188.  
  2189. function IQueryable:preparsed_query( query, lifetime )
  2190. return query_raw( self, query, lifetime, false, true )
  2191. end
  2192.  
  2193. function IQueryable:preparsed_query_tracked( query, lifetime )
  2194. return query_raw( self, query, lifetime, true, true )
  2195. end
  2196.  
  2197. function setf( self, properties )
  2198. local prop_setters = {}
  2199.  
  2200. for k, v in pairs( properties ) do
  2201. prop_setters[#prop_setters + 1] = { k, "set_" .. k, v }
  2202. end
  2203.  
  2204. for i = 1, #self do
  2205. local vals = self[i].values
  2206. for n = 1, #prop_setters do
  2207. if vals:has( prop_setters[n][1] ) then
  2208. self[i][prop_setters[n][2]]( self[i], prop_setters[n][3] )
  2209. end
  2210. end
  2211. end
  2212. end
  2213.  
  2214. function addtag( self, tag )
  2215. for i = 1, #self do
  2216. self[i]:add_tag( tag )
  2217. end
  2218. end
  2219.  
  2220. function remtag( self, tag )
  2221. for i = 1, #self do
  2222. self[i]:remove_tag( tag )
  2223. end
  2224. end
  2225.  
  2226. function query_raw( self, query, lifetime, track, parsed )
  2227. if not parsed then
  2228. lifetime = {}
  2229. parameters.check( 1, "query", "string", query )
  2230. local parser = DynamicValueParser( Stream( query ) )
  2231.  
  2232. parser.enable_queries = true
  2233. query = parser:parse_query()
  2234. end
  2235.  
  2236. local query_f, init_f
  2237. local nodes = self.collated_children
  2238. local matches = { set = setf, add_tag = addtag, remove_tag = remtag }
  2239. local n, ID = 0
  2240.  
  2241. local function updater() -- this can definitely be optimised
  2242. local n = 1
  2243.  
  2244. for i = 1, #nodes do
  2245. if query_f( nodes[i] ) then
  2246. if matches[n] ~= nodes[i] then
  2247. table.insert( matches, n, nodes[i] )
  2248. self.query_tracker:invoke_child_change( ID, nodes[i], "child-added" )
  2249. end
  2250. n = n + 1
  2251. elseif matches[n] == nodes[i] then
  2252. table.remove( matches, n )
  2253. self.query_tracker:invoke_child_change( ID, nodes[i], "child-removed" )
  2254. end
  2255. end
  2256. end
  2257.  
  2258. query_f, init_f = Codegen.node_query( query, lifetime, updater )
  2259.  
  2260. init_f( self )
  2261.  
  2262. for i = 1, #nodes do
  2263. if query_f( nodes[i] ) then
  2264. n = n + 1
  2265. matches[n] = nodes[i]
  2266. end
  2267. end
  2268.  
  2269. if track then
  2270. ID = self.query_tracker:track( query_f, matches )
  2271.  
  2272. self.query_tracker.lifetimes[ID] = lifetime
  2273.  
  2274. return matches, ID
  2275. else
  2276. if not parsed then
  2277. for i = #lifetime, 1, -1 do
  2278. local l = lifetime[i]
  2279. lifetime[i] = nil
  2280. if l[1] == "value" then
  2281. l[2].values:unsubscribe( l[3], l[4] )
  2282. elseif l[1] == "query" then
  2283. l[2]:unsubscribe( l[3], l[4] )
  2284. elseif l[1] == "tag" then
  2285. l[2]:unsubscribe_from_tag( l[3], l[4] )
  2286. end
  2287. end
  2288. end
  2289.  
  2290. return matches
  2291. end
  2292. end
  2293.  
  2294.  
  2295.  
  2296.  
  2297. IChildContainer = class.new_interface( "IChildContainer", ICollatedChildren, IQueryable ) {
  2298. children = {};
  2299. application = nil;
  2300. }
  2301.  
  2302. function IChildContainer:IChildContainer()
  2303. self.children = {}
  2304.  
  2305. self.meta.__add = self.add_child
  2306.  
  2307. function self.meta:__concat( child )
  2308. self:add_child( child )
  2309. return self
  2310. end
  2311. end
  2312.  
  2313. function IChildContainer:child_value_changed( child )
  2314. self.query_tracker:update( "child-changed", child )
  2315.  
  2316. if self.parent then
  2317. return self.parent:child_value_changed( child )
  2318. end
  2319. end
  2320.  
  2321. function IChildContainer:add_child( child )
  2322. parameters.check( 1, "child", Sheet, child )
  2323.  
  2324. local children = self.children
  2325. local collated = self.collated_children
  2326.  
  2327. if child.parent then
  2328. child.parent:remove_child( child, true )
  2329. end
  2330.  
  2331. local index = #children + 1
  2332.  
  2333. for i = 1, #children do
  2334. if children[i].z > child.z then
  2335. index = i
  2336. break
  2337. end
  2338. end
  2339.  
  2340. local c, l = children[index], index <= #children
  2341.  
  2342. table.insert( children, index, child )
  2343. self:update_collated( "child-added", child, l and (c:implements( ICollatedChildren ) and c.collated_children[1] or c) or self )
  2344. self:set_changed()
  2345.  
  2346. if child:implements( ICollatedChildren ) then
  2347. for i = 1, #child.collated_children do
  2348. child.collated_children[i].application = self.application
  2349. child.collated_children[i].values:trigger "application"
  2350. end
  2351. end
  2352.  
  2353. child.parent = self
  2354. child.application = self.application
  2355. child.values:trigger "parent"
  2356. child.values:trigger "application"
  2357. child.values:child_inserted()
  2358.  
  2359. return child
  2360. end
  2361.  
  2362. function IChildContainer:remove_child( child, reinsert )
  2363. for i = 1, #self.children do
  2364. if self.children[i] == child then
  2365. child.parent = nil
  2366. child.application = nil
  2367.  
  2368. table.remove( self.children, i )
  2369. self:set_changed()
  2370. self:update_collated( "child-removed", child )
  2371.  
  2372. if child:implements( ICollatedChildren ) then
  2373. for i = 1, #child.collated_children do
  2374. child.collated_children[i].application = nil
  2375. child.collated_children[i].values:trigger "application"
  2376. end
  2377. end
  2378.  
  2379. child.values:trigger "parent"
  2380. child.values:trigger "application"
  2381.  
  2382. if not reinsert then
  2383. child.values:child_removed()
  2384. end
  2385.  
  2386. return child
  2387. end
  2388. end
  2389. end
  2390.  
  2391. function IChildContainer:get_children()
  2392. local c = {}
  2393. local children = self.children
  2394.  
  2395. for i = 1, #children do
  2396. c[i] = children[i]
  2397. end
  2398.  
  2399. return c
  2400. end
  2401.  
  2402. function IChildContainer:get_children_at( x, y )
  2403. parameters.check( 2, "x", "number", x, "y", "number", y )
  2404.  
  2405. local c = self:get_children()
  2406. local elements = {}
  2407.  
  2408. for i = #c, 1, -1 do
  2409. c[i]:handle( MouseEvent( 6, x - c[i].x, y - c[i].y, elements, true ) )
  2410. end
  2411.  
  2412. return elements
  2413. end
  2414.  
  2415. function IChildContainer:is_child_visible( child )
  2416. parameters.check( 1, "child", Sheet, child )
  2417.  
  2418. return child.x + child.width > 0 and child.y + child.height > 0 and child.x < self.width and child.y < self.height
  2419. end
  2420.  
  2421. function IChildContainer:reposition_child_z_index( child )
  2422. local children = self.children
  2423.  
  2424. for i = 1, #children do
  2425. if children[i] == child then
  2426. local moved = false
  2427.  
  2428. while children[i-1] and children[i-1].z > child.z do
  2429. children[i-1], children[i] = child, children[i-1]
  2430. moved = true
  2431. i = i - 1
  2432. end
  2433.  
  2434. while children[i+1] and children[i+1].z < child.z do
  2435. children[i+1], children[i] = child, children[i+1]
  2436. moved = true
  2437. i = i + 1
  2438. end
  2439.  
  2440. if moved then
  2441. self:update_collated( "child-removed", child )
  2442. self:update_collated( "child-added", child, i + 1 > #children and self or children[i + 1]:implements( ICollatedChildren ) and children[i + 1].collated_children[1] or children[i + 1] )
  2443. self:set_changed()
  2444. end
  2445.  
  2446. break
  2447. end
  2448. end
  2449. end
  2450.  
  2451.  
  2452.  
  2453.  
  2454. ITagged = class.new_interface( "ITagged", nil ) {
  2455. tags = {};
  2456. subscriptions = {};
  2457. id = "ID";
  2458. }
  2459.  
  2460. function ITagged:ITagged()
  2461. self.tags = {}
  2462. self.subscriptions = {}
  2463. end
  2464.  
  2465. function ITagged:add_tag( tag )
  2466. self.tags[tag] = true
  2467.  
  2468. if self.parent then
  2469. self.parent:child_value_changed( self )
  2470. end
  2471.  
  2472. return self:trigger( tag )
  2473. end
  2474.  
  2475. function ITagged:remove_tag( tag )
  2476. self.tags[tag] = ni
  2477.  
  2478. if self.parent then
  2479. self.parent:child_value_changed( self )
  2480. end
  2481.  
  2482. return self:trigger( tag )
  2483. end
  2484.  
  2485. function ITagged:has_tag( tag )
  2486. return self.tags[tag] or false
  2487. end
  2488.  
  2489. function ITagged:toggle_tag( tag )
  2490. self.tags[tag] = not self.tags[tag] or nil
  2491.  
  2492. if self.parent then
  2493. self.parent:child_value_changed( self )
  2494. end
  2495.  
  2496. return self:trigger( tag )
  2497. end
  2498.  
  2499. function ITagged:set_ID( id ) -- TODO: make this a dynamic property
  2500. self.id = tostring( id )
  2501.  
  2502. if self.parent then
  2503. self.parent:child_value_changed( self )
  2504. end
  2505.  
  2506. return self
  2507. end
  2508.  
  2509. function ITagged:subscribe_to_tag( tag, lifetime, callback )
  2510. self.subscriptions[tag] = self.subscriptions[tag] or {}
  2511. self.subscriptions[tag][#self.subscriptions[tag] + 1] = callback
  2512. lifetime[#lifetime + 1] = { "tag", self, tag, callback }
  2513.  
  2514. return callback
  2515. end
  2516.  
  2517. function ITagged:unsubscribe_from_tag( tag, f )
  2518. if self.subscriptions[tag] then
  2519. for i = #self.subscriptions[tag], 1, -1 do
  2520. if self.subscriptions[tag][i] == f then
  2521. return table.remove( self.subscriptions[tag], i )
  2522. end
  2523. end
  2524. end
  2525. end
  2526.  
  2527. function ITagged:trigger( tag )
  2528. if self.subscriptions[tag] then
  2529. for i = #self.subscriptions[tag], 1, -1 do
  2530. self.subscriptions[tag][i]()
  2531. end
  2532. end
  2533.  
  2534. return self
  2535. end
  2536.  
  2537.  
  2538.  
  2539.  
  2540. ISize = class.new_interface( "ISize", nil ) {
  2541. width = 0;
  2542. height = 0;
  2543. }
  2544.  
  2545. function ISize:ISize()
  2546. self.values:add( "width", 0, { update_surface_size = true } )
  2547. self.values:add( "height", 0, { update_surface_size = true } )
  2548. end
  2549.  
  2550.  
  2551.  
  2552.  
  2553. ITimer = class.new_interface( "ITimer", nil ) {
  2554. timerID = 0;
  2555. time = nil;
  2556. lt = nil;
  2557. timers = {};
  2558. }
  2559.  
  2560. function ITimer:ITimer()
  2561. self.time = os.clock()
  2562. self.timers = {}
  2563. self:step_timer()
  2564. end
  2565.  
  2566. function ITimer:new_timer( n )
  2567. parameters.check( 1, "n", "number", n )
  2568.  
  2569. local finish, ID = self.time + n, nil -- avoids duplicating timer events
  2570. for i = 1, #self.timers do
  2571. if self.timers[i].time == finish then
  2572. ID = self.timers[i].ID
  2573. break
  2574. end
  2575. end
  2576. return ID or os.startTimer( n )
  2577. end
  2578.  
  2579. function ITimer:queue( response, n )
  2580. parameters.check( 2, "response", "function", response, "n", "number", n )
  2581.  
  2582. local timer_id = self:new_timer( n )
  2583. local finish = self.time + n
  2584. self.timers[#self.timers + 1] = { time = finish, response = response, ID = timer_id }
  2585. return timer_id
  2586. end
  2587.  
  2588. function ITimer:cancel_timer( ID )
  2589. parameters.check( 1, "ID", "number", ID )
  2590.  
  2591. for i = #self.timers, 1, -1 do
  2592. if self.timers[i].ID == ID then
  2593. table.remove( self.timers, i )
  2594. break
  2595. end
  2596. end
  2597.  
  2598. return self
  2599. end
  2600.  
  2601. function ITimer:step_timer()
  2602. self.lt = self.time
  2603. self.time = os.clock()
  2604.  
  2605. return self
  2606. end
  2607.  
  2608. function ITimer:get_timer_delta()
  2609. return self.time - self.lt
  2610. end
  2611.  
  2612. function ITimer:update_timer( timer_id )
  2613. local updated = false
  2614.  
  2615. for i = #self.timers, 1, -1 do
  2616. if self.timers[i].ID == timer_id then
  2617. table.remove( self.timers, i ).response()
  2618. updated = true
  2619. end
  2620. end
  2621.  
  2622. return updated
  2623. end
  2624.  
  2625.  
  2626.  
  2627.  
  2628.  
  2629. Event = class.new( "Event", nil, nil ) {
  2630. event = "Event";
  2631. }
  2632.  
  2633. function Event:is( event )
  2634. return self.event == event
  2635. end
  2636.  
  2637. function Event:handle( handler )
  2638. self.handled = true
  2639. self.handler = handler
  2640. end
  2641.  
  2642.  
  2643.  
  2644.  
  2645. KeyboardEvent = class.new( "KeyboardEvent", Event, nil ) {
  2646. event = "KeyboardEvent";
  2647. key = 0;
  2648. held = {};
  2649. }
  2650.  
  2651. function KeyboardEvent:KeyboardEvent( event, key, held )
  2652. self.event = event
  2653. self.key = key
  2654. self.held = held
  2655. end
  2656.  
  2657. function KeyboardEvent:matches( hotkey )
  2658. local t, segment2
  2659.  
  2660. for segment in hotkey:gmatch "(.-)%-" do
  2661. if segment == "ctrl" or segment == "shift" or segment == "alt" then
  2662. segment = segment:sub( 1, 1 ):upper() .. segment:sub( 2 )
  2663. segment2 = "right" .. segment
  2664. segment = "left" .. segment
  2665.  
  2666. if self.held[segment2] then
  2667. if self.held[segment] then
  2668. segment = self.held[segment] < self.held[segment2] and (not t or self.held[segment] > t) and segment or segment2
  2669. else
  2670. segment = segment2
  2671. end
  2672. end
  2673. end
  2674.  
  2675. if not self.held[segment] or ( t and self.held[segment] < t ) then
  2676. return false
  2677. end
  2678.  
  2679. t = self.held[segment]
  2680. end
  2681.  
  2682. return self.key == keys[hotkey:gsub( ".+%-", "" )]
  2683. end
  2684.  
  2685. function KeyboardEvent:is_held( key )
  2686. return self.key == keys[key] or self.held[key]
  2687. end
  2688.  
  2689.  
  2690.  
  2691.  
  2692. MiscEvent = class.new( "MiscEvent", Event, nil ) {
  2693. event = "MiscEvent";
  2694. parameters = {};
  2695. }
  2696.  
  2697. function MiscEvent:MiscEvent( event, ... )
  2698. self.event = event
  2699. self.parameters = { ... }
  2700. end
  2701.  
  2702.  
  2703.  
  2704.  
  2705. MouseEvent = class.new( "MouseEvent", Event, nil ) {
  2706. event = "MouseEvent";
  2707. x = 0;
  2708. y = 0;
  2709. button = 0;
  2710. within = true;
  2711. }
  2712.  
  2713. function MouseEvent:MouseEvent( event, x, y, button, within )
  2714. self.event = event
  2715. self.x = x
  2716. self.y = y
  2717. self.button = button
  2718. self.within = within
  2719. end
  2720.  
  2721. function MouseEvent:is_within_area( x, y, width, height )
  2722. parameters.check( 4,
  2723. "x", "number", x,
  2724. "y", "number", y,
  2725. "width", "number", width,
  2726. "height", "number", height
  2727. )
  2728.  
  2729. return self.x >= x and self.y >= y and self.x < x + width and self.y < y + height
  2730. end
  2731.  
  2732. function MouseEvent:clone( x, y, within )
  2733. parameters.check( 2,
  2734. "x", "number", x,
  2735. "y", "number", y
  2736. )
  2737.  
  2738. local sub = MouseEvent( self.event, self.x - x, self.y - y, self.button, self.within and within or false )
  2739. sub.handled = self.handled
  2740.  
  2741. function sub.handle()
  2742. sub.handled = true
  2743. self:handle()
  2744. end
  2745.  
  2746. return sub
  2747. end
  2748.  
  2749.  
  2750.  
  2751.  
  2752. TextEvent = class.new( "TextEvent", Event, nil ) {
  2753. event = "TextEvent";
  2754. text = "";
  2755. }
  2756.  
  2757. function TextEvent:TextEvent( event, text )
  2758. self.event = event
  2759. self.text = text
  2760. end
  2761.  
  2762.  
  2763.  
  2764.  
  2765.  
  2766. local property_cache = {}
  2767.  
  2768. local CHANGECODE_NO_TRANSITION, CHANGECODE_TRANSITION, SELF_INDEX_UPDATER,
  2769. ARBITRARY_DOTINDEX_UPDATER, ARBITRARY_INDEX_UPDATER, DYNAMIC_QUERY_UPDATER,
  2770. QUERY_UPDATER, GENERIC_SETTER, STRING_CASTING, RAW_STRING_CASTING,
  2771. INTEGER_CASTING, RAW_INTEGER_CASTING, NUMBER_CASTING, RAW_NUMBER_CASTING,
  2772. COLOUR_CASTING, RAW_COLOUR_CASTING, ALIGNMENT_CASTING,
  2773. RAW_ALIGNMENT_CASTING, ERR_CASTING
  2774.  
  2775. local node_query_internal, dynamic_value_internal
  2776.  
  2777. Codegen = class.new( "Codegen", nil, nil ) {
  2778.  
  2779. }
  2780.  
  2781. function Codegen.node_query( parsed_query, lifetime, updater )
  2782. local names = {}
  2783. local named_values = {}
  2784. local val_names = {}
  2785. local init_localised = {}
  2786. local initialise_code = {}
  2787. local tracked = {}
  2788. local query_str = node_query_internal( parsed_query, "n", tracked )
  2789. local tl = #tracked
  2790.  
  2791. for i = 1, tl do
  2792. names[i] = "n" .. i
  2793. named_values[i] = tracked[i].value
  2794. init_localised[i] = "f" .. i
  2795. init_localised[tl + i] = "i" .. i
  2796. val_names[i] = "v" .. i
  2797. initialise_code[i] = "f" .. i .. ", i" .. i .. " = Codegen.dynamic_value( n" .. i .. ", lifetime, env, n, function()\n"
  2798. .. "\tv" .. i .. " = f" .. i .. "()\n"
  2799. .. "\treturn updater()\n"
  2800. .. "end )"
  2801. end
  2802.  
  2803. for i = 1, tl do
  2804. initialise_code[i + tl] = "i" .. i .. "()"
  2805. end
  2806.  
  2807. for i = 1, tl do
  2808. initialise_code[i + tl + tl] = "v" .. i .. " = f" .. i .. "()"
  2809. end
  2810.  
  2811. local code = "local lifetime, updater" .. (#names == 0 and "" or ", " .. table.concat( names, ", " )) .. " = ...\n"
  2812. .. (#val_names == 0 and "" or "local " .. table.concat( val_names, ", " ) .. "\n")
  2813. .. "return function( n )\n"
  2814. .. "\treturn " .. query_str
  2815. .. "\nend, function( n )\n"
  2816. .. "\tlocal env = {}\n"
  2817. .. (#init_localised == 0 and "" or "\tlocal " .. table.concat( init_localised, ", " ) .. "\n")
  2818. .. table.concat( initialise_code, "\n" )
  2819. .. "\nend"
  2820.  
  2821. local f, err = assert( (load or loadstring)( code, "query", nil, _ENV ) )
  2822.  
  2823. if setfenv then
  2824. setfenv( f, getfenv() )
  2825. end
  2826.  
  2827. local getter, initialiser = f( lifetime, updater, unpack( named_values ) )
  2828. return getter, initialiser
  2829. end
  2830.  
  2831. function Codegen.dynamic_value( parsed_value, lifetime, env, obj, updater )
  2832. local names = {}
  2833. local functions = {}
  2834. local inputs = {}
  2835. local state = {
  2836. environment = env;
  2837. object = obj;
  2838. names = names;
  2839. functions = functions;
  2840. inputs = inputs;
  2841. }
  2842. local return_value = dynamic_value_internal( parsed_value, state )
  2843.  
  2844. local roots = {}
  2845. local roots_tocheck = { return_value }
  2846. local i = 1
  2847. local func_compiled = {}
  2848. local initialisers = {}
  2849. local initialise_function
  2850. local input_names = {}
  2851.  
  2852. for i = 1, #inputs do
  2853. input_names[i] = "i" .. i
  2854. end
  2855.  
  2856. while i <= #roots_tocheck do
  2857. local t = roots_tocheck[i]
  2858. if #t.dependencies == 0 then
  2859. roots[#roots + 1] = t
  2860. else
  2861. local added = false
  2862. for n = 1, #t.dependencies do
  2863. if t.dependencies[n].update or t.dependencies[n].initialise then
  2864. roots_tocheck[#roots_tocheck + 1] = t.dependencies[n]
  2865. added = true
  2866. end
  2867. end
  2868. if not added then
  2869. roots[#roots + 1] = t
  2870. end
  2871. end
  2872. i = i + 1
  2873. end
  2874.  
  2875. for i = 1, #functions do
  2876. local dependants = {}
  2877. local tocheck = { functions[i].node }
  2878. local index = 1
  2879. local update_root = false
  2880.  
  2881. while index <= #tocheck do
  2882. if index ~= 1 then
  2883. dependants[#dependants + 1] = tocheck[index].update
  2884. end
  2885.  
  2886. if index == 1 or not tocheck[index].complex then
  2887. update_root = update_root or tocheck[index] == return_value
  2888.  
  2889. local idx = #tocheck
  2890. for n = 1, #tocheck[index].dependants do
  2891. tocheck[idx + n] = tocheck[index].dependants[n]
  2892. end
  2893. end
  2894.  
  2895. index = index + 1
  2896. end
  2897.  
  2898. if update_root then
  2899. dependants[#dependants + 1] = "updater()"
  2900. end
  2901.  
  2902. if dependants[1] then
  2903. dependants[#dependants] = "return " .. dependants[#dependants]
  2904. end
  2905.  
  2906. func_compiled[i] = functions[i].code:gsub( "DEPENDENCIES", table.concat( dependants, "\n" ) )
  2907. end
  2908.  
  2909. local i = 1
  2910. while i <= #roots do
  2911. initialisers[#initialisers + 1] = roots[i].initialise or roots[i].update
  2912.  
  2913. if not roots[i].complex then
  2914. for n = 1, #roots[i].dependants do
  2915. roots[#roots + 1] = roots[i].dependants[n]
  2916. end
  2917. end
  2918.  
  2919. i = i + 1
  2920. end
  2921.  
  2922. local s = initialisers[#initialisers]
  2923.  
  2924. if s and s:find "^f%d+%(%)" then
  2925. if #initialisers == 1 then
  2926. initialise_function = s:match "^f%d+"
  2927. else
  2928. initialisers[#initialisers] = "return " .. s
  2929. end
  2930. end
  2931.  
  2932. local code
  2933. = "local self, lifetime, updater"
  2934. .. (#inputs > 0 and ", " .. table.concat( input_names, ", ") or "")
  2935. .. " = ...\n"
  2936. .. (state.tostringed and "local tostring = tostring\n" or "")
  2937. .. (state.floored and "local floor = math.floor\n" or "")
  2938. .. (#names > 0 and "local " .. table.concat( names, ", " ) .. "\n" or "")
  2939. .. table.concat( func_compiled, "\n" ) .. "\n"
  2940. .. "return function() return " .. return_value.value .. " end, "
  2941. .. (initialise_function or "function()\n"
  2942. .. table.concat( initialisers, "\n" )
  2943. .. (#initialisers == 0 and "" or "\n") .. "end")
  2944.  
  2945. if parsed_value.type == "binary operator expression" and parsed_value.lvalue.lvalue and parsed_value.lvalue.lvalue.type == "tag" then
  2946. local h = fs.open( "demo/log.txt", "w" )
  2947. h.write( code )
  2948. h.close()
  2949. end
  2950.  
  2951. local f, err = assert( (load or loadstring)( code, "dynamic value", nil, _ENV ) )
  2952.  
  2953. if setfenv then
  2954. setfenv( f, getfenv() )
  2955. end
  2956.  
  2957. local getter, initialiser = f( obj, lifetime, updater, unpack( inputs ) )
  2958. return getter, initialiser
  2959. end
  2960.  
  2961. function Codegen.dynamic_property_setter( property, options )
  2962. property_cache[property] = property_cache[property] or {}
  2963. options = options or {}
  2964.  
  2965. local self_changed = ValueHandler.properties[property].change == "self"
  2966. local parent_changed = ValueHandler.properties[property].change == "parent"
  2967. local ptype = ValueHandler.properties[property].type
  2968.  
  2969. local t1 = {}
  2970. local t2 = {}
  2971. local t3 = {}
  2972. local t4 = {}
  2973. local t5 = {}
  2974.  
  2975. if options.update_surface_size then
  2976. t4[#t4 + 1] = "if self.surface then self.surface = surface.create( self.width, self.height ) end"
  2977. self_changed = true
  2978. end
  2979.  
  2980. if self_changed then
  2981. t4[#t4 + 1] = "if not self.changed then self:set_changed() end"
  2982. elseif parent_changed then
  2983. t4[#t4 + 1] = "if self.parent then self.parent:set_changed() end"
  2984. end
  2985.  
  2986. if self_changed or parent_changed then
  2987. t4[#t4 + 1] = "if self.parent then self.parent:child_value_changed( self ) end"
  2988. end
  2989.  
  2990. if ptype == Type.primitive.string then
  2991. t1[#t1 + 1] = "if value:sub( 1, 1 ) == '!' then value = value:sub( 2 ) else value = ('%q'):format( value ) end"
  2992. end
  2993.  
  2994. if ptype == Type.sheets.colour then
  2995. for k, v in pairs( colour ) do
  2996. t2[#t2 + 1] = "environment." .. k .. " = { type = rtype, value = " .. v .. " }"
  2997. end
  2998.  
  2999. t5[#t5 + 1] = "if value == 0 then value = nil end"
  3000. end
  3001.  
  3002. if ptype == Type.sheets.alignment then
  3003. for k, v in pairs( alignment ) do
  3004. t2[#t2 + 1] = "environment." .. k .. " = { type = rtype, value = " .. v .. " }"
  3005. end
  3006. end
  3007.  
  3008. t4[#t4 + 1] = options.custom_update_code
  3009.  
  3010. local s5 = table.concat( t5, "\n" ) -- code to update the value before assignment
  3011. local s4 = table.concat( t4, "\n" ) -- code to run on value update
  3012. local s3 = table.concat( t3, "\n" ) -- code to update the AST
  3013. local s2 = table.concat( t2, "\n" ) -- code to change the environment
  3014. local s1 = table.concat( t1, "\n" ) -- code to update the string value
  3015.  
  3016. for i = 1, #property_cache[property] do
  3017. local c = property_cache[property][i]
  3018. if c[1] == s1 and c[2] == s2 and c[3] == s3 and c[4] == s4 and c[5] == s5 then
  3019. return c.f
  3020. end
  3021. end
  3022.  
  3023. local change_code
  3024.  
  3025. if ValueHandler.properties[property].transitionable then
  3026. change_code = CHANGECODE_TRANSITION
  3027.  
  3028. if s4 ~= "" then
  3029. change_code = change_code
  3030. :gsub( "CUSTOM_UPDATE", ", function( self )\n" .. s4 .. "\nend" )
  3031. :gsub( "PROPERTY_TRANSITION_QUOTED", ("%q"):format( property .. "_transition" ) )
  3032. :gsub( "PROCESS_VALUE", s5 )
  3033. end
  3034. else
  3035. change_code = CHANGECODE_NO_TRANSITION
  3036. :gsub( "ONCHANGE", s4 )
  3037. :gsub( "PROCESS_VALUE", s5 )
  3038. end
  3039.  
  3040. local prop_quoted = ("%q"):format( property )
  3041. local caster = ptype == Type.primitive.string and STRING_CASTING
  3042. or ptype == Type.primitive.integer and INTEGER_CASTING
  3043. or ptype == Type.primitive.number and NUMBER_CASTING
  3044. or ptype == Type.sheets.colour and COLOUR_CASTING
  3045. or ptype == Type.sheets.alignment and ALIGNMENT_CASTING
  3046. or ERR_CASTING
  3047. local rawcaster = ptype == Type.primitive.string and RAW_STRING_CASTING
  3048. or ptype == Type.primitive.integer and RAW_INTEGER_CASTING
  3049. or ptype == Type.primitive.number and RAW_NUMBER_CASTING
  3050. or ptype == Type.sheets.colour and RAW_COLOUR_CASTING
  3051. or ptype == Type.sheets.alignment and RAW_ALIGNMENT_CASTING
  3052. or ERR_CASTING
  3053. local str = GENERIC_SETTER
  3054. :gsub( "CHANGECODE", change_code )
  3055. :gsub( "PROPERTY_QUOTED", ("%q"):format( property ) )
  3056. :gsub( "RAW_PROPERTY", ("%q"):format( "raw_" .. property ) )
  3057. :gsub( "VALUE_MODIFICATION", function() return s1 end )
  3058. :gsub( "ENV_MODIFICATION", function() return s2 end )
  3059. :gsub( "AST_MODIFICATION", function() return s3 end )
  3060. :gsub( "CASTING_RAW", function() return rawcaster end )
  3061. :gsub( "CASTING", function() return caster end )
  3062. local f = assert( (load or loadstring)( str, "property setter '" .. property .. "'", nil, _ENV ) )
  3063.  
  3064. if setfenv then
  3065. setfenv( f, getfenv() )
  3066. end
  3067.  
  3068. local fr = f( ptype )
  3069.  
  3070. property_cache[property][#property_cache[property] + 1] = { s1, s2, s3, s4, s5, f = fr }
  3071.  
  3072. return fr
  3073. end
  3074.  
  3075. CHANGECODE_NO_TRANSITION = [[
  3076. PROCESS_VALUE
  3077. self[PROPERTY_QUOTED] = value
  3078. ONCHANGE
  3079. self.values:trigger PROPERTY_QUOTED]]
  3080.  
  3081. CHANGECODE_TRANSITION = [[
  3082. PROCESS_VALUE
  3083. self.values:transition( PROPERTY_QUOTED, value, self[PROPERTY_TRANSITION_QUOTED]CUSTOM_UPDATE )]]
  3084.  
  3085. STRING_CASTING = [[
  3086. if value_type == Type.primitive.integer or value_type == Type.primitive.number or value_type == Type.primitive.boolean then
  3087. value_parsed = {
  3088. type = "tostring";
  3089. value = value_parsed;
  3090. }
  3091. else
  3092. error "TODO: fix this error"
  3093. end
  3094. ]]
  3095.  
  3096. RAW_STRING_CASTING = [[
  3097. if value_type == Type.primitive.integer or value_type == Type.primitive.number or value_type == Type.primitive.boolean then
  3098. value = tostring( value )
  3099. else
  3100. error "TODO: fix this error"
  3101. end
  3102. ]]
  3103.  
  3104. INTEGER_CASTING = [[
  3105. if value_type == Type.primitive.number then
  3106. value_parsed = {
  3107. type = "floor";
  3108. value = value_parsed;
  3109. }
  3110. else
  3111. error "TODO: fix this error"
  3112. end
  3113. ]]
  3114.  
  3115.  
  3116.  
  3117. RAW_INTEGER_CASTING = [[
  3118. if value_type == Type.primitive.number then
  3119. value = math.floor( value )
  3120. else
  3121. error "TODO: fix this error"
  3122. end
  3123. ]]
  3124.  
  3125. NUMBER_CASTING = [[
  3126. if not (value_type == Type.primitive.integer) then
  3127. error "TODO: fix this error"
  3128. end
  3129. ]]
  3130.  
  3131. RAW_NUMBER_CASTING = NUMBER_CASTING
  3132.  
  3133. COLOUR_CASTING = [[
  3134. error "TODO: fix this error"
  3135. ]]
  3136.  
  3137. RAW_COLOUR_CASTING = [[
  3138. if value_type == Type.primitive.integer then
  3139. if value ~= 0 and (math.log( value ) / math.log( 2 ) % 1 ~= 0 or value < 1 or value > 2 ^ 15) then
  3140. error "TODO: fix this error"
  3141. end
  3142. else
  3143. error "TODO: fix this error"
  3144. end
  3145. ]]
  3146.  
  3147. ALIGNMENT_CASTING = [[
  3148. error "TODO: fix this error"
  3149. ]]
  3150.  
  3151. RAW_ALIGNMENT_CASTING = [[
  3152. if value_type == Type.primitive.integer then
  3153. if value ~= 0 and value ~= 2 and value ~= 3 and value ~= 4 and value ~= 1 then
  3154. error "TODO: fix this error"
  3155. end
  3156. else
  3157. error "TODO: fix this error"
  3158. end
  3159. ]]
  3160.  
  3161. ERR_CASTING = [[
  3162. error "TODO: fix this error"
  3163. ]]
  3164.  
  3165. SELF_INDEX_UPDATER = [[function FUNC()
  3166. NAME = self.INDEX
  3167. DEPENDENCIES
  3168. end]]
  3169.  
  3170. ARBITRARY_DOTINDEX_UPDATER = [[do
  3171. local function f0()
  3172. DEPENDENCIES
  3173. end
  3174.  
  3175. function FUNC()
  3176. local obj = LVALUE
  3177.  
  3178. if NAME then
  3179. NAME.values:unsubscribe( "INDEX", f0 )
  3180. end
  3181.  
  3182. if obj then
  3183. obj.values:subscribe( "INDEX", lifetime, f0 )
  3184. end
  3185.  
  3186. NAME = obj
  3187. return f0()
  3188. end
  3189. end]]
  3190.  
  3191. TAG_CHECK_UPDATER = [[do
  3192. local function f0()
  3193. VALUE = NAME and NAME:has_tag TAG
  3194. DEPENDENCIES
  3195. end
  3196.  
  3197. function FUNC()
  3198. local obj = LVALUE
  3199.  
  3200. if NAME then
  3201. NAME:unsubscribe_from_tag( TAG, f0 )
  3202. end
  3203.  
  3204. if obj then
  3205. obj:subscribe_to_tag( TAG, lifetime, f0 )
  3206. end
  3207.  
  3208. NAME = obj
  3209. return f0()
  3210. end
  3211. end]]
  3212.  
  3213. ARBITRARY_INDEX_UPDATER = [[do
  3214. local function f0()
  3215. NAME = OLDVALUE and OLDINDEX and OLDVALUE[OLDINDEX]
  3216. DEPENDENCIES
  3217. end
  3218.  
  3219. function FUNC()
  3220. local obj = LVALUE
  3221. local idx = INDEX
  3222.  
  3223. if OLDVALUE and type( OLDINDEX ) == "string" then
  3224. OLDVALUE.values:unsubscribe( OLDINDEX, f0 )
  3225. end
  3226.  
  3227. if obj and type( idx ) == "string" then
  3228. obj.values:subscribe( idx, lifetime, f0 )
  3229. end
  3230.  
  3231. OLDVALUE = obj
  3232. OLDINDEX = idx
  3233. return f0()
  3234. end
  3235. end]]
  3236.  
  3237. DYNAMIC_QUERY_UPDATER = [[do
  3238. local elems, ID
  3239.  
  3240. local function f0()
  3241. NAME = elems and elems[1]
  3242. DEPENDENCIES
  3243. end
  3244.  
  3245. function FUNC()
  3246. local object = SOURCE
  3247.  
  3248. if PREVSOURCE then
  3249. PREVSOURCE.query_tracker:unsubscribe( ID, f0 )
  3250. end
  3251.  
  3252. if object then
  3253. elems, ID = object:preparsed_query_tracked( QDATA, lifetime )
  3254. object.query_tracker:subscribe( ID, lifetime, f0 )
  3255. end
  3256.  
  3257. PREVSOURCE = object
  3258. return f0()
  3259. end
  3260. end]]
  3261.  
  3262. QUERY_UPDATER = [[function FUNC()
  3263. local object = SOURCE
  3264.  
  3265. if object then
  3266. local elems = object:preparsed_query( QDATA, lifetime )
  3267. NAME = elems[1]
  3268.  
  3269. if NAME then
  3270. FUNC = function()end
  3271.  
  3272. DEPENDENCIES
  3273. end
  3274. end
  3275. end]]
  3276.  
  3277. GENERIC_SETTER = [[
  3278. local rtype = ...
  3279. return function( self, value )
  3280. self.values:respawn PROPERTY_QUOTED
  3281. self[RAW_PROPERTY] = value
  3282.  
  3283. if type( value ) ~= "string" then
  3284. local value_type = Typechecking.resolve_type( value )
  3285.  
  3286. if not (value_type == rtype) then
  3287. print( value_type, rtype )
  3288. CASTING_RAW
  3289. end
  3290.  
  3291. CHANGECODE
  3292.  
  3293. return self
  3294. end
  3295.  
  3296. VALUE_MODIFICATION
  3297.  
  3298. local parser = DynamicValueParser( Stream( value ) )
  3299. local environment = {}
  3300.  
  3301. parser.flags.enable_queries = true
  3302.  
  3303. ENV_MODIFICATION
  3304.  
  3305. local value_parsed = parser:parse_expression()
  3306. or "TODO: fix this error"
  3307.  
  3308. AST_MODIFICATION
  3309.  
  3310. local value_parsed, value_type = Typechecking.check_type( value_parsed, {
  3311. object = self;
  3312. environment = environment;
  3313. } )
  3314. local lifetime = self.values.lifetimes[PROPERTY_QUOTED]
  3315. local default = self.values .defaults[PROPERTY_QUOTED]
  3316. local setter_f, initialiser_f
  3317.  
  3318. if not (value_type == rtype) then
  3319. CASTING
  3320. end
  3321.  
  3322. local function update()
  3323. local value = setter_f( self ) or default
  3324.  
  3325. if value ~= self[PROPERTY_QUOTED] then
  3326. CHANGECODE
  3327. end
  3328. end
  3329.  
  3330. if not parser.stream:is_EOF() then
  3331. error "TODO: fix this error"
  3332. end
  3333.  
  3334. setter_f, initialiser_f = Codegen.dynamic_value( value_parsed, lifetime, environment, self, update )
  3335.  
  3336. initialiser_f()
  3337. update()
  3338.  
  3339. return self
  3340. end]]
  3341.  
  3342. function node_query_internal( query, name, tracked )
  3343. if query.type == "id" then
  3344. return ("%s.id=='%s'"):format( name, query.value )
  3345. elseif query.type == "tag" then
  3346. return ("%s:has_tag'%s'"):format( name, query.value )
  3347. elseif query.type == "any" then
  3348. return "true"
  3349. elseif query.type == "class" then
  3350. return ("%s:type():lower()=='%s'"):format( name, query.value:lower() )
  3351. elseif query.type == "negate" then
  3352. local i = node_query_internal( query.value, name, tracked )
  3353. return i == "true" and "false" or i == "false" and "true" or "not (" .. i .. ")"
  3354. elseif query.type == "attributes" then
  3355. local t = {}
  3356. local idx = #tracked + 1
  3357.  
  3358. for i = 1, #query.attributes do
  3359. local attr = query.attributes[i]
  3360. local op = attr.comparison
  3361.  
  3362. if op == "=" then
  3363. op = "=="
  3364. end
  3365.  
  3366. tracked[idx] = { value = attr.value }
  3367. t[i] = "v" .. idx .. " and " .. name .. "." .. attr.name .. " " .. op .. " v" .. idx
  3368. idx = idx + 1
  3369. end
  3370.  
  3371. return table.concat( t, " and " )
  3372. elseif query.type == "operator" then
  3373. if query.operator == "&" then
  3374. local lvalue = node_query_internal( query.lvalue, name, tracked )
  3375. local rvalue = node_query_internal( query.rvalue, name, tracked )
  3376.  
  3377. if lvalue == "true" then return rvalue end
  3378. if rvalue == "true" then return lvalue end
  3379. if lvalue == "false" then return lvalue end
  3380. if rvalue == "false" then return rvalue end
  3381.  
  3382. return lvalue .. " and " .. rvalue
  3383. elseif query.operator == "|" then
  3384. local lvalue = node_query_internal( query.lvalue, name, tracked )
  3385. local rvalue = node_query_internal( query.rvalue, name, tracked )
  3386.  
  3387. if lvalue == "true" then return lvalue end
  3388. if rvalue == "true" then return rvalue end
  3389. if lvalue == "false" then return rvalue end
  3390. if rvalue == "false" then return lvalue end
  3391.  
  3392. return "(" .. lvalue .. " or " .. rvalue .. ")"
  3393. elseif query.operator == ">" then
  3394. local lvalue = node_query_internal( query.lvalue, name .. ".parent", tracked )
  3395. local rvalue = node_query_internal( query.rvalue, name, tracked )
  3396.  
  3397. if lvalue == "true" then return name .. ".parent and " .. rvalue end
  3398. if rvalue == "true" then return name .. ".parent and " .. lvalue end
  3399. if lvalue == "false" then return lvalue end
  3400. if rvalue == "false" then return rvalue end
  3401.  
  3402. return rvalue .. " and " .. name .. ".parent and " .. lvalue
  3403. end
  3404. end
  3405. end
  3406.  
  3407. function dynamic_value_internal( value, state )
  3408. if not value then return error "here" end
  3409. if value.type == "integer"
  3410. or value.type == "float"
  3411. or value.type == "boolean" then
  3412. return {
  3413. value = tostring( value.value );
  3414. complex = false;
  3415. update = nil;
  3416. initialise = nil;
  3417. dependants = {};
  3418. dependencies = {};
  3419. }
  3420.  
  3421. elseif value.type == "string" then
  3422. return {
  3423. value = ("%q"):format( value.value );
  3424. complex = false;
  3425. update = nil;
  3426. initialise = nil;
  3427. dependants = {};
  3428. dependencies = {};
  3429. }
  3430.  
  3431. elseif value.type == "self" then
  3432. return {
  3433. value = "self";
  3434. complex = false;
  3435. update = nil;
  3436. initialise = nil;
  3437. dependants = {};
  3438. dependencies = {};
  3439. }
  3440.  
  3441. elseif value.type == "parent" then
  3442. if state.object:type_of( Application ) then
  3443. error "TODO: fix this error"
  3444. else
  3445. local nr = #state.names + 1
  3446. local nu = #state.names + 2
  3447. local t = {
  3448. value = "n" .. nr;
  3449. complex = true;
  3450. update = "f" .. nu .. "()";
  3451. initialise = "self.values:subscribe( 'parent', lifetime, f" .. nu .. " )\nf" .. nu .. "()";
  3452. dependants = {};
  3453. dependencies = {};
  3454. }
  3455.  
  3456. state.names[nr] = "n" .. nr
  3457. state.names[nu] = "f" .. nu
  3458. state.functions[#state.functions + 1] = {
  3459. code = SELF_INDEX_UPDATER:gsub( "NAME", "n" .. nr ):gsub( "INDEX", "parent" ):gsub( "FUNC", "f" .. nu );
  3460. node = t;
  3461. }
  3462.  
  3463. return t
  3464. end
  3465.  
  3466. elseif value.type == "application" then
  3467. if state.object:type_of( Application ) then
  3468. return {
  3469. value = "self";
  3470. complex = false;
  3471. update = nil;
  3472. initialise = nil;
  3473. dependants = {};
  3474. dependencies = {};
  3475. }
  3476.  
  3477. else
  3478. local nr = #state.names + 1
  3479. local nu = #state.names + 2
  3480. local t = {
  3481. value = "n" .. nr;
  3482. complex = true;
  3483. update = "f" .. nu .. "()";
  3484. initialise = "self.values:subscribe( 'application', lifetime, f" .. nu .. " )\nf" .. nu .. "()";
  3485. dependants = {};
  3486. dependencies = {};
  3487. }
  3488.  
  3489. state.names[nr] = "n" .. nr
  3490. state.names[nu] = "f" .. nu
  3491. state.functions[#state.functions + 1] = {
  3492. code = SELF_INDEX_UPDATER:gsub( "NAME", "n" .. nr ):gsub( "INDEX", "application" ):gsub( "FUNC", "f" .. nu );
  3493. node = t;
  3494. }
  3495.  
  3496. return t
  3497. end
  3498.  
  3499. elseif value.type == "identifier" then
  3500. if state.environment[value.value] ~= nil then
  3501. state.inputs[#state.inputs + 1] = state.environment[value.value].value;
  3502.  
  3503. return {
  3504. value = "i" .. #state.inputs;
  3505. complex = false;
  3506. update = nil;
  3507. initialise = nil;
  3508. dependants = {};
  3509. dependencies = {};
  3510. }
  3511.  
  3512. else
  3513. error "TODO: fix this error"
  3514. end
  3515.  
  3516. elseif value.type == "percentage" then
  3517. error "NYI"
  3518.  
  3519. elseif value.type == "unary operator expression" then
  3520. local val = dynamic_value_internal( value.value, state )
  3521. local n = #state.names + 1
  3522. local t = {
  3523. value = "n" .. n;
  3524. complex = false;
  3525. update = "n" .. n .. " = " .. val.value .. " ~= nil and " .. value.operator .. " " .. val.value .. " or nil";
  3526. initialise = nil;
  3527. dependants = {};
  3528. dependencies = { val };
  3529. }
  3530.  
  3531. state.names[n] = "n" .. n
  3532. val.dependants[#val.dependants + 1] = t
  3533.  
  3534. return t
  3535.  
  3536. elseif value.type == "call" then
  3537. local val = dynamic_value_internal( value.value, state )
  3538. local params = {}
  3539. local params_strval = {}
  3540. local n = #state.names + 1
  3541.  
  3542. for i = 1, #value.parameters do
  3543. params[i] = dynamic_value_internal( value.parameters[i], state )
  3544. params_strval[i] = params[i].value
  3545. end
  3546.  
  3547. local t = {
  3548. value = "n" .. n;
  3549. complex = false;
  3550. update = "n" .. n .. " = " .. val.value .. " ~= nil and " .. table.concat( params_strval, " ~= nil and " ) .. " ~= nil and " .. val.value .. "(" .. table.concat( params_strval, ", " ) .. ") or nil";
  3551. initialise = nil;
  3552. dependants = {};
  3553. dependencies = { val, unpack( params ) };
  3554. }
  3555.  
  3556. state.names[n] = "n" .. n
  3557. val.dependants[#val.dependants + 1] = t
  3558.  
  3559. for i = 1, #params do
  3560. params[i].dependants[#params[i].dependants + 1] = t
  3561. end
  3562.  
  3563. return t
  3564.  
  3565. elseif value.type == "index" then
  3566. local val = dynamic_value_internal( value.value, state )
  3567. local idx = dynamic_value_internal( value.index, state )
  3568. local nval = #state.names + 1 -- copy of the value
  3569. local nidx = #state.names + 2 -- copy of the index
  3570. local nret = #state.names + 3 -- return value
  3571. local npdt = #state.names + 4 -- updater function
  3572. local t = {
  3573. value = "n" .. nret;
  3574. complex = true;
  3575. update = "f" .. npdt .. "()";
  3576. initialise = nil;
  3577. dependants = {};
  3578. dependencies = { val, idx };
  3579. }
  3580.  
  3581. val.dependants[#val.dependants + 1] = t;
  3582. idx.dependants[#idx.dependants + 1] = t;
  3583. state.names[nval] = "n" .. nval
  3584. state.names[nidx] = "n" .. nidx
  3585. state.names[nret] = "n" .. nret
  3586. state.names[npdt] = "f" .. npdt
  3587. state.functions[#state.functions + 1] = {
  3588. code = ARBITRARY_INDEX_UPDATER
  3589. :gsub( "NAME", "n" .. nret )
  3590. :gsub( "FUNC", "f" .. npdt )
  3591. :gsub( "OLDVALUE", "n" .. nval )
  3592. :gsub( "OLDINDEX", "n" .. nidx )
  3593. :gsub( "LVALUE", val.value )
  3594. :gsub( "INDEX", idx.value );
  3595. node = t;
  3596. }
  3597.  
  3598. return t
  3599.  
  3600. elseif value.type == "binary operator expression" then
  3601. local lvalue = dynamic_value_internal( value.lvalue, state )
  3602. local rvalue = dynamic_value_internal( value.rvalue, state )
  3603. local n = #state.names + 1
  3604. local t = {
  3605. value = "n" .. n;
  3606. complex = false;
  3607. update = "n" .. n .. " = " .. (
  3608. (value.operator == "or" and lvalue.value .. " or " .. rvalue.value)
  3609. or (value.operator == "and" and lvalue.value .. " and " .. rvalue.value .. " or nil")
  3610. -- or value.operator == "==" and "" -- potentially $abc == $def == true if both are undefined
  3611. -- or value.operator == "~=" and "" -- potentially $abc != $def == true if one is undefined and false if both are undefined
  3612. or (lvalue.value .. " ~= nil and " .. rvalue.value .. " ~= nil and " .. lvalue.value .. " " .. value.operator .. " " .. rvalue.value .. " or nil")
  3613. );
  3614. initialise = nil;
  3615. dependants = {};
  3616. dependencies = { lvalue, rvalue };
  3617. }
  3618.  
  3619. state.names[n] = "n" .. n
  3620. lvalue.dependants[#lvalue.dependants + 1] = t
  3621. rvalue.dependants[#rvalue.dependants + 1] = t
  3622.  
  3623. return t
  3624.  
  3625. elseif value.type == "dotindex" then
  3626. local val = dynamic_value_internal( value.value, state )
  3627. local nr = #state.names + 1
  3628. local nu = #state.names + 2
  3629. local t = {
  3630. value = "(n" .. nr .. " and n" .. nr .. "." .. value.index .. ")";
  3631. complex = true;
  3632. update = "f" .. nu .. "()";
  3633. initialise = nil;
  3634. dependants = {};
  3635. dependencies = { val };
  3636. }
  3637.  
  3638. state.names[nr] = "n" .. nr
  3639. state.names[nu] = "f" .. nu
  3640. state.functions[#state.functions + 1] = {
  3641. code = ARBITRARY_DOTINDEX_UPDATER
  3642. :gsub( "NAME", "n" .. nr )
  3643. :gsub( "INDEX", value.index )
  3644. :gsub( "FUNC", "f" .. nu )
  3645. :gsub( "LVALUE", val.value );
  3646. node = t;
  3647. }
  3648.  
  3649. val.dependants[#val.dependants + 1] = t
  3650.  
  3651. return t
  3652.  
  3653. elseif value.type == "query" then
  3654. local val = dynamic_value_internal( value.source, state )
  3655. local nret = #state.names + 1
  3656. local npdt = #state.names + 2
  3657. local t = {
  3658. value = "n" .. nret;
  3659. complex = true;
  3660. update = "f" .. npdt .. "()";
  3661. initialise = nil;
  3662. dependants = {};
  3663. dependencies = { val };
  3664. }
  3665.  
  3666. state.inputs[#state.inputs + 1] = value.query
  3667. state.names[nret] = "n" .. nret
  3668. state.names[npdt] = "f" .. npdt
  3669. state.functions[#state.functions + 1] = {
  3670. code = QUERY_UPDATER
  3671. :gsub( "NAME", "n" .. nret )
  3672. :gsub( "SOURCE", val.value )
  3673. :gsub( "QDATA", "i" .. #state.inputs )
  3674. :gsub( "FUNC", "f" .. npdt );
  3675. node = t;
  3676. }
  3677.  
  3678. val.dependants[#val.dependants + 1] = t
  3679.  
  3680. return t
  3681.  
  3682. elseif value.type == "dynamic query" then
  3683. local val = dynamic_value_internal( value.source, state )
  3684. local nret = #state.names + 1
  3685. local nsrc = #state.names + 2
  3686. local npdt = #state.names + 3
  3687. local t = {
  3688. value = "n" .. nret;
  3689. complex = true;
  3690. update = "f" .. npdt .. "()";
  3691. initialise = nil;
  3692. dependants = {};
  3693. dependencies = { val };
  3694. }
  3695.  
  3696. state.inputs[#state.inputs + 1] = value.query
  3697. state.names[nret] = "n" .. nret
  3698. state.names[nsrc] = "n" .. nsrc
  3699. state.names[npdt] = "f" .. npdt
  3700. state.functions[#state.functions + 1] = {
  3701. code = DYNAMIC_QUERY_UPDATER
  3702. :gsub( "NAME", "n" .. nret )
  3703. :gsub( "PREVSOURCE", "n" .. nsrc )
  3704. :gsub( "SOURCE", val.value )
  3705. :gsub( "QDATA", "i" .. #state.inputs )
  3706. :gsub( "FUNC", "f" .. npdt );
  3707. node = t;
  3708. }
  3709.  
  3710. val.dependants[#val.dependants + 1] = t
  3711.  
  3712. return t
  3713.  
  3714. elseif value.type == "floor" then
  3715. local val = dynamic_value_internal( value.value, state )
  3716. local n = #state.names + 1
  3717. local t = {
  3718. value = "n" .. n;
  3719. complex = false;
  3720. update = "n" .. n .. " = " .. val.value .. " ~= nil and floor( " .. val.value .. " ) or nil";
  3721. initialise = nil;
  3722. dependants = {};
  3723. dependencies = { val };
  3724. }
  3725.  
  3726. state.names[n] = "n" .. n
  3727. val.dependants[#val.dependants + 1] = t
  3728. state.floored = true
  3729.  
  3730. return t
  3731.  
  3732. elseif value.type == "tostring" then
  3733. local val = dynamic_value_internal( value.value, state )
  3734. local n = #state.names + 1
  3735. local t = {
  3736. value = "n" .. n;
  3737. complex = false;
  3738. update = "n" .. n .. " = " .. val.value .. " ~= nil and tostring( " .. val.value .. " ) or nil";
  3739. initialise = nil;
  3740. dependants = {};
  3741. dependencies = { val };
  3742. }
  3743.  
  3744. state.names[n] = "n" .. n
  3745. val.dependants[#val.dependants + 1] = t
  3746. state.tostringed = true
  3747.  
  3748. return t
  3749.  
  3750. elseif value.type == "tag" then
  3751. local val = dynamic_value_internal( value.value, state )
  3752. local nidx = #state.names + 1
  3753. local nval = #state.names + 2
  3754. local npdt = #state.names + 3
  3755. local t = {
  3756. value = "n" .. nval;
  3757. complex = true;
  3758. update = "f" .. npdt .. "()";
  3759. initialise = nil;
  3760. dependants = {};
  3761. dependencies = { val };
  3762. }
  3763.  
  3764. state.names[nidx] = "n" .. nidx
  3765. state.names[nval] = "n" .. nval
  3766. state.names[npdt] = "f" .. npdt
  3767. state.functions[#state.functions + 1] = {
  3768. code = TAG_CHECK_UPDATER
  3769. :gsub( "NAME", "n" .. nidx )
  3770. :gsub( "TAG", ("%q"):format( value.tag ) )
  3771. :gsub( "FUNC", "f" .. npdt )
  3772. :gsub( "LVALUE", val.value )
  3773. :gsub( "VALUE", "n" .. nval );
  3774. node = t;
  3775. }
  3776.  
  3777. val.dependants[#val.dependants + 1] = t
  3778.  
  3779. return t
  3780.  
  3781. else
  3782. -- TODO: every other type of node
  3783. error "TODO: fix this error"
  3784. end
  3785. end
  3786.  
  3787.  
  3788.  
  3789.  
  3790. local is_operator = {
  3791. ["+"] = true;
  3792. ["-"] = true;
  3793. ["*"] = true;
  3794. ["/"] = true;
  3795. ["%"] = true;
  3796. ["^"] = true;
  3797. ["&"] = true;
  3798. ["|"] = true;
  3799. [">"] = true;
  3800. ["<"] = true;
  3801. [">="] = true;
  3802. ["<="] = true;
  3803. ["!="] = true;
  3804. ["=="] = true;
  3805. }
  3806.  
  3807. local op_precedences = {
  3808. ["|"] = 0;
  3809. ["&"] = 1;
  3810. ["!="] = 2;
  3811. ["=="] = 2;
  3812. [">"] = 3;
  3813. ["<"] = 3;
  3814. [">="] = 3;
  3815. ["<="] = 3;
  3816. ["+"] = 4;
  3817. ["-"] = 4;
  3818. ["*"] = 5;
  3819. ["/"] = 5;
  3820. ["%"] = 5;
  3821. ["^"] = 6;
  3822. }
  3823.  
  3824. local lua_operators = {
  3825. ["|"] = "or";
  3826. ["&"] = "and";
  3827. ["!="] = "~=";
  3828. }
  3829.  
  3830. local function parse_name( stream )
  3831. return stream:skip_value( "identifier" )
  3832. end
  3833.  
  3834. DynamicValueParser = class.new( "DynamicValueParser", nil, nil ) {
  3835. stream = nil;
  3836. flags = {};
  3837. }
  3838.  
  3839. function DynamicValueParser:DynamicValueParser( stream )
  3840. self.stream = stream
  3841. self.flags = {}
  3842. end
  3843.  
  3844. function DynamicValueParser:parse_primary_expression()
  3845. if self.stream:skip( "float", "self" ) then
  3846. return { type = "self" }
  3847.  
  3848. elseif self.stream:skip( "float", "application" ) then
  3849. return { type = "application" }
  3850.  
  3851. elseif self.stream:skip( "float", "parent" ) then
  3852. return { type = "parent" }
  3853.  
  3854. elseif self.stream:test( "identifier" ) then
  3855. return { type = "identifier", value = parse_name( self.stream ) }
  3856.  
  3857. elseif self.stream:test( "int" ) then
  3858. return { type = "integer", value = self.stream:next().value }
  3859.  
  3860. elseif self.stream:test( "float" ) then
  3861. return { type = "float", value = self.stream:next().value }
  3862.  
  3863. elseif self.stream:test( "float" ) then
  3864. return { type = "boolean", value = self.stream:next().value }
  3865. elseif self.stream:test( "string" ) then
  3866. return { type = "string", value = self.stream:next().value }
  3867. elseif self.stream:test( "symbol", "$" ) then
  3868. if self.flags.enable_queries then
  3869. self.stream:next()
  3870. else
  3871. error "TODO: fix this error"
  3872. end
  3873.  
  3874. local dynamic = not self.stream:skip( "symbol", "$" )
  3875. local query = self:parse_query_term( true )
  3876.  
  3877. return { type = dynamic and "dynamic query" or "query", query = query, source = { type = "application" } }
  3878. elseif self.stream:skip( "symbol", "(" ) then
  3879. local expr = self:parse_expression() or error "TODO: fix this error"
  3880.  
  3881. return self.stream:skip( "symbol", ")" ) and expr or error "TODO: fix this error"
  3882. end
  3883.  
  3884. return nil
  3885. end
  3886.  
  3887. function DynamicValueParser:parse_term()
  3888. local operators = {}
  3889.  
  3890. while self.stream:test( "symbol", "#" )
  3891. or self.stream:test( "symbol", "!" )
  3892. or self.stream:test( "symbol", "-" )
  3893. or self.stream:test( "symbol", "+" ) do
  3894. operators[#operators + 1] = self.stream:next().value
  3895. end
  3896.  
  3897. local term = self:parse_primary_expression()
  3898.  
  3899. while term do
  3900. if self.stream:skip( "symbol", "." ) then
  3901. local index = parse_name( self.stream )
  3902. or self.stream:skip_value( "float", "parent" )
  3903. or self.stream:skip_value( "float", "application" )
  3904. or error "TODO: fix this error"
  3905.  
  3906. term = { type = "dotindex", value = term, index = index }
  3907.  
  3908. elseif self.stream:skip( "symbol", "#" ) then
  3909. local tag = parse_name( self.stream )
  3910. or self.stream:skip_value( "float" )
  3911. or error "TODO: fix this error"
  3912.  
  3913. term = { type = "tag", value = term, tag = tag }
  3914.  
  3915. elseif self.stream:skip( "symbol", "(" ) then
  3916. local parameters = {}
  3917.  
  3918. while self.stream:skip( "whitespace" ) do end
  3919.  
  3920. if not self.stream:skip( "symbol", ")" ) then
  3921. repeat
  3922. while self.stream:skip( "whitespace" ) do end
  3923. parameters[#parameters + 1] = self:parse_expression() or error "TODO: fix this error"
  3924. while self.stream:skip( "whitespace" ) do end
  3925. until not self.stream:skip( "symbol", "," )
  3926.  
  3927. if not self.stream:skip( "symbol", ")" ) then
  3928. error "TODO: fix this error"
  3929. end
  3930. end
  3931.  
  3932. term = { type = "call", value = term, parameters = parameters }
  3933.  
  3934. elseif self.stream:skip( "symbol", "[" ) then
  3935. while self.stream:skip( "whitespace" ) do end
  3936. local index = self:parse_expression() or error "TODO: fix this error"
  3937. while self.stream:skip( "whitespace" ) do end
  3938.  
  3939. if not self.stream:skip( "symbol", "]" ) then
  3940. error "TODO: fix this error"
  3941. end
  3942.  
  3943. term = { type = "index", value = term, index = index }
  3944.  
  3945. elseif self.stream:test( "symbol", "$" ) then
  3946. if self.flags.enable_queries then
  3947. self.stream:next()
  3948. else
  3949. error "TODO: fix this error"
  3950. end
  3951.  
  3952. local dynamic = not self.stream:skip( "symbol", "$" )
  3953. local query = self:parse_query_term( true )
  3954.  
  3955. term = { type = dynamic and "dynamic query" or "query", query = query, source = term }
  3956. elseif self.stream:test( "symbol", "%" ) then
  3957. if self.flags.enable_percentages then
  3958. self.stream:next()
  3959. else
  3960. error "TODO: fix this error"
  3961. end
  3962.  
  3963. term = { type = "percentage", value = term }
  3964. else
  3965. break
  3966. end
  3967. end
  3968.  
  3969. for i = #operators, 1, -1 do
  3970. term = term and { type = "unary operator expression", value = term, operator = operators[i] }
  3971. end
  3972.  
  3973. return term
  3974. end
  3975.  
  3976. function DynamicValueParser:parse_expression()
  3977. local operand_stack = { self:parse_term() }
  3978. local operator_stack = {}
  3979. local precedences = {}
  3980.  
  3981. if #operand_stack == 0 then
  3982. return nil
  3983. end
  3984.  
  3985. while self.stream:skip( "whitespace" ) do end
  3986.  
  3987. while self.stream:test( "symbol" ) and is_operator[self.stream:peek().value] do
  3988. local op = self.stream:next().value
  3989. local prec = op_precedences[op]
  3990.  
  3991. while precedences[1] and precedences[#precedences] >= prec do
  3992. local rvalue = table.remove( operand_stack, #operand_stack )
  3993.  
  3994. table.remove( precedences, #precedences )
  3995.  
  3996. operand_stack[#operand_stack] = {
  3997. type = "binary operator expression";
  3998. operator = table.remove( operator_stack, #operator_stack );
  3999. lvalue = operand_stack[#operand_stack];
  4000. rvalue = rvalue;
  4001. }
  4002. end
  4003.  
  4004. while self.stream:skip( "whitespace" ) do end
  4005.  
  4006. operand_stack[#operand_stack + 1] = self:parse_term() or error "TODO: fix this"
  4007. operator_stack[#operator_stack + 1] = lua_operators[op] or op
  4008. precedences[#precedences + 1] = prec
  4009.  
  4010. while self.stream:skip( "whitespace" ) do end
  4011. end
  4012.  
  4013. while precedences[1] do
  4014. local rvalue = table.remove( operand_stack, #operand_stack )
  4015.  
  4016. table.remove( precedences, #precedences )
  4017.  
  4018. operand_stack[#operand_stack] = {
  4019. type = "binary operator expression";
  4020. operator = table.remove( operator_stack, #operator_stack );
  4021. lvalue = operand_stack[#operand_stack];
  4022. rvalue = rvalue;
  4023. }
  4024. end
  4025.  
  4026. return operand_stack[1]
  4027. end
  4028.  
  4029. function DynamicValueParser:parse_query_term( in_dynamic_value )
  4030. local negation_count, obj = 0
  4031.  
  4032. while self.stream:skip( "symbol", "!" ) do
  4033. negation_count = negation_count + 1
  4034. end
  4035.  
  4036. if self.stream:test( "identifier" ) or self.stream:skip( "symbol", "#" ) then -- ID
  4037. obj = { type = "id", value = parse_name( self.stream ) or error "TODO: fix this error" }
  4038. ID_parsed = true
  4039. elseif self.stream:skip( "symbol", "*" ) then
  4040. obj = { type = "any" }
  4041. elseif self.stream:skip( "symbol", "?" ) then
  4042. obj = { type = "class", value = parse_name( self.stream ) or error "TODO: fix this error" }
  4043. elseif self.stream:skip( "symbol", "(" ) then
  4044. print( self.stream:peek().value )
  4045. obj = self:parse_query()
  4046.  
  4047. if not self.stream:skip( "symbol", ")" ) then
  4048. error "TODO: fix this error"
  4049. end
  4050. end
  4051.  
  4052. local tags = {}
  4053.  
  4054. while (not in_dynamic_value or not obj) and self.stream:skip( "symbol", "." ) do -- tags
  4055. local tag = { type = "tag", value = parse_name( self.stream ) or error "TODO: fix this error" }
  4056.  
  4057. if obj then
  4058. obj = { type = "operator", operator = "&", lvalue = obj, rvalue = tag }
  4059. else
  4060. obj = tag
  4061. end
  4062. end
  4063.  
  4064. if self.stream:skip( "symbol", "[" ) then
  4065. local attributes = {}
  4066.  
  4067. repeat
  4068. local name = parse_name( self.stream ) or error "TODO: fix this error"
  4069.  
  4070. while self.stream:skip( "whitespace" ) do end
  4071.  
  4072. local comparison
  4073. = self.stream:skip_value( "symbol", "=" )
  4074. or self.stream:skip_value( "symbol", ">" )
  4075. or self.stream:skip_value( "symbol", "<" )
  4076. or self.stream:skip_value( "symbol", ">=" )
  4077. or self.stream:skip_value( "symbol", "<=" )
  4078. or self.stream:skip_value( "symbol", "!=" )
  4079. or error "TODO: fix this"
  4080.  
  4081. while self.stream:skip( "whitespace" ) do end
  4082.  
  4083. local value = self:parse_expression() or error "TODO: fix this error"
  4084.  
  4085. attributes[#attributes + 1] = {
  4086. name = name;
  4087. comparison = comparison;
  4088. value = value;
  4089. }
  4090. until not self.stream:skip( "symbol", "," )
  4091.  
  4092. if not self.stream:skip( "symbol", "]" ) then
  4093. error "TODO: fix this error"
  4094. end
  4095.  
  4096. obj = obj and {
  4097. type = "operator";
  4098. rvalue = obj;
  4099. lvalue = { type = "attributes", attributes = attributes };
  4100. operator = "&";
  4101. } or { type = "attributes", attributes = attributes }
  4102. end
  4103.  
  4104. if not obj then
  4105. error "TODO: fix this error"
  4106. end
  4107.  
  4108. if negation_count % 2 == 1 then
  4109. obj = { type = "negate", value = obj }
  4110. end
  4111.  
  4112. return obj
  4113. end
  4114.  
  4115. function DynamicValueParser:parse_query( in_dynamic_value )
  4116. local operands = { self:parse_query_term( in_dynamic_value ) }
  4117. local operators = {}
  4118.  
  4119. while self.stream:skip( "whitespace" ) do end
  4120.  
  4121. while self.stream:test( "symbol" ) do
  4122. local prec = operator_list[self.stream:peek().value]
  4123.  
  4124. if prec then
  4125. while operators[1] and operator_list[operators[#operators]] >= prec do -- assumming left associativity for all operators
  4126. operands[#operands - 1] = {
  4127. type = "operator";
  4128. lvalue = operands[#operands - 1];
  4129. rvalue = table.remove( operands, #operands );
  4130. operator = table.remove( operators, #operators );
  4131. }
  4132. end
  4133.  
  4134. operators[#operators + 1] = self.stream:next().value
  4135.  
  4136. while self.stream:skip( "whitespace" ) do end
  4137.  
  4138. operands[#operands + 1] = self:parse_query_term( in_dynamic_value )
  4139.  
  4140. while self.stream:skip( "whitespace" ) do end
  4141. else
  4142. break
  4143. end
  4144. end
  4145.  
  4146. while operators[1] do
  4147. operands[#operands - 1] = {
  4148. type = "operator";
  4149. lvalue = operands[#operands - 1];
  4150. rvalue = table.remove( operands, #operands );
  4151. operator = table.remove( operators, #operators );
  4152. }
  4153. end
  4154.  
  4155. return operands[1]
  4156. end
  4157.  
  4158.  
  4159.  
  4160.  
  4161. QueryTracker=class.new("QueryTracker",nil,nil){
  4162. parent=nil;
  4163. queries={};
  4164. lifetimes={};
  4165. subscriptions={};
  4166. ID=0;
  4167. }
  4168.  
  4169. function QueryTracker:QueryTracker(parent)
  4170. self.parent=parent
  4171. self.queries={}
  4172. self.lifetimes={}
  4173. self.subscriptions={}
  4174. end
  4175.  
  4176. function QueryTracker:track(query,nodes)
  4177. local ID=self.ID
  4178.  
  4179. self.queries[#self.queries+1]={query,nodes,ID}
  4180. self.ID=ID+1
  4181. self.lifetimes[ID]={}
  4182.  
  4183. return ID
  4184. end
  4185.  
  4186. function QueryTracker:is_tracking(ID)
  4187. for i=1,#self.queries do
  4188. if self.queries[i][3]==ID then
  4189. return true
  4190. end
  4191. end
  4192.  
  4193. return false
  4194. end
  4195.  
  4196. function QueryTracker:get_query(ID)
  4197. for i=1,#self.queries do
  4198. if self.queries[i][3]==ID then
  4199. return self.queries[i]
  4200. end
  4201. end
  4202. end
  4203.  
  4204. function QueryTracker:untrack(ID)
  4205. for i=#self.queries,1,-1 do
  4206. if self.queries[i][3]==ID then
  4207. local t=self.lifetimes[ID]
  4208.  
  4209.  
  4210. for i=#t,1,-1 do
  4211. local l=t[i]
  4212. t[i]=nil
  4213. if l[1]=="value"then
  4214. l[2].values:unsubscribe(l[3],l[4])
  4215. elseif l[1]=="query"then
  4216. l[2]:unsubscribe(l[3],l[4])
  4217. elseif l[1]=="tag"then
  4218. l[2]:unsubscribe_from_tag(l[3],l[4])
  4219. end
  4220. end
  4221.  
  4222. self.lifetimes[ID]=nil
  4223. self.subscriptions[ID]=nil
  4224.  
  4225. return table.remove(self.queries,i)
  4226. end
  4227. end
  4228. end
  4229.  
  4230. function QueryTracker:subscribe(ID,lifetime,callback)
  4231. local t=self.subscriptions[ID]or{}
  4232.  
  4233. lifetime[#lifetime+1]={"query",self,ID,callback}
  4234. self.subscriptions[ID]=t
  4235. t[#t+1]=callback
  4236. end
  4237.  
  4238. function QueryTracker:unsubscribe(ID,callback)
  4239. if self.subscriptions[ID]then
  4240. for i=#self.subscriptions[ID],1,-1 do
  4241. if self.subscriptions[ID][i]==callback then
  4242. if#self.subscriptions[ID]==1 then
  4243. self:untrack(ID)
  4244. else
  4245. table.remove(self.subscriptions[ID],i)
  4246. end
  4247.  
  4248. return callback
  4249. end
  4250. end
  4251. end
  4252. end
  4253.  
  4254. function QueryTracker:update(mode,child)
  4255. for i=1,#self.queries do
  4256. local add,remove=(mode=="child-added"or mode=="child-changed")and self.queries[i][1](child),mode=="child-removed"
  4257.  
  4258. if mode=="child-changed"and not add then
  4259. remove=true
  4260. end
  4261.  
  4262. if add then
  4263. local nodes=self.queries[i][2]
  4264. local collated=self.parent.collated_children
  4265. local n=1
  4266.  
  4267. for i=1,#collated do
  4268. if collated[i]==child then
  4269. break
  4270. elseif collated[i]==nodes[n]then
  4271. n=n+1
  4272. end
  4273. end
  4274.  
  4275. if nodes[n]~=child then--if it's not already in the query
  4276. table.insert(nodes,n,child)
  4277. self:invoke_child_change(self.queries[i][3],child,"child-added")
  4278. else
  4279. self:invoke_child_change(self.queries[i][3],child,"child-changed")
  4280. end
  4281. elseif remove then
  4282. local t=self.queries[i][2]
  4283.  
  4284. for n=1,#t do
  4285. if t[n]==child then
  4286. table.remove(t,n)
  4287. self:invoke_child_change(self.queries[i][3],child,"child-removed")
  4288.  
  4289. break
  4290. end
  4291. end
  4292. end
  4293. end
  4294. end
  4295.  
  4296. function QueryTracker:invoke_child_change(query_ID,child,mode)
  4297. local callbacks=self.subscriptions[query_ID]or{}
  4298.  
  4299. for i=1,#callbacks do
  4300. callbacks[i](mode,child)
  4301. end
  4302. end
  4303.  
  4304.  
  4305.  
  4306.  
  4307. local escape_chars={
  4308. ["n"]="\n";
  4309. ["r"]="\r";
  4310. ["t"]="\t";
  4311. }
  4312.  
  4313. local symbols={
  4314. ["("]=true;[")"]=true;
  4315. ["["]=true;["]"]=true;
  4316. ["{"]=true;["}"]=true;
  4317. ["."]=true;[":"]=true;
  4318. [","]=true;[";"]=true;
  4319. ["="]=true;
  4320. ["$"]=true;
  4321. ["+"]=true;["-"]=true;
  4322. ["*"]=true;["/"]=true;
  4323. ["%"]=true;["^"]=true;
  4324. ["#"]=true;
  4325. ["!"]=true;
  4326. ["&"]=true;["|"]=true;
  4327. ["?"]=true;
  4328. [">"]=true;["<"]=true;
  4329. [">="]=true;["<="]=true;
  4330. ["!="]=true;["=="]=true;
  4331. }
  4332.  
  4333. local keywords={
  4334. ["self"]=true;
  4335. ["application"]=true;
  4336. ["parent"]=true;
  4337. }
  4338.  
  4339. Stream=class.new("Stream",nil,nil){
  4340. position=1;
  4341. line=1;
  4342. character=1;
  4343. text="";
  4344. }
  4345.  
  4346. function Stream:Stream(text)
  4347. self.text=text
  4348. end
  4349.  
  4350. function Stream:consume_string()
  4351. local text=self.text
  4352. local close=text:sub(self.position,self.position)
  4353. local escaped=false
  4354. local sub=string.sub
  4355. local str={}
  4356.  
  4357. for i=self.position+1,#text do
  4358. local char=sub(text,i,i)
  4359.  
  4360. if char=="\n"then
  4361. self.line=self.line+1
  4362. self.character=0
  4363. end
  4364.  
  4365. if escaped then
  4366. str[#str+1]=escape_chars[char]or"\\"..char
  4367. elseif char=="\\"then
  4368. escaped=true
  4369. elseif char==close then
  4370. self.position=i+1
  4371. return{type="string",value=table.concat(str),position={
  4372. character=char,line=line;
  4373. }}
  4374. else
  4375. str[#str+1]=char
  4376. end
  4377.  
  4378. self.character=self.character+1
  4379. end
  4380.  
  4381. error("TODO:fix this error")
  4382. end
  4383.  
  4384. function Stream:consume_identifier()
  4385. local word=self.text:match("[%w_]+",self.position)
  4386. local char=self.character
  4387. local type=keywords[word]and"float"
  4388. or(word=="true"or word=="false"and"float")
  4389. or"identifier"
  4390.  
  4391. self.position=self.position+#word
  4392. self.character=self.character+#word
  4393.  
  4394. return{type=type,value=word,position={
  4395. character=char,line=self.line;
  4396. }}
  4397. end
  4398.  
  4399. function Stream:consume_number()
  4400. local char=self.character
  4401. local num=self.text:match("%d*%.?%d+e[%+%-]?%d+",self.position)
  4402. or self.text:match("%d*%.?%d+",self.position)
  4403. local type=(num:find"%."or num:find"e%-")
  4404. and"float"or"int"
  4405.  
  4406. self.position=self.position+#num
  4407. self.character=self.character+#num
  4408.  
  4409. return{type=type,value=num,position={
  4410. character=char,line=line;
  4411. }}
  4412. end
  4413.  
  4414. function Stream:consume_whitespace()
  4415. local line,char=self.line,self.character
  4416. local type="whitespace"
  4417. local value="\n"
  4418.  
  4419. if self.text:sub(1,1)=="\n"then
  4420. self.line=self.line+1
  4421. self.position=self.position+1
  4422. self.character=1
  4423. type="newline"
  4424. else
  4425. local n=#self.text:match("^[^%S\n]+",self.position)
  4426.  
  4427. value=self.text:sub(self.position,self.position+n-1)
  4428. self.position=self.position+n
  4429. self.character=self.character+n
  4430. end
  4431.  
  4432. return{type=type,value=value,position={
  4433. character=char,line=line;
  4434. }}
  4435. end
  4436.  
  4437. function Stream:consume_symbol()
  4438. local text=self.text
  4439. local sub=string.sub
  4440. local pos=self.position
  4441. local s3=sub(text,pos,pos+2)
  4442. local s2=sub(text,pos,pos+1)
  4443. local s1=sub(text,pos,pos+0)
  4444. local value=s1
  4445. local char=self.character
  4446.  
  4447. if symbols[s3]then
  4448. value=s3
  4449. elseif symbols[s2]then
  4450. value=s2
  4451. elseif not symbols[s1]then
  4452. print(s1,s2,s3)
  4453. error("TODO:fix this error")
  4454. end
  4455.  
  4456. self.character=self.character+#value
  4457. self.position=self.position+#value
  4458.  
  4459. return{type="symbol",value=value,position={
  4460. character=char,line=self.line;
  4461. }}
  4462. end
  4463.  
  4464. function Stream:consume()
  4465. if self.position>#self.text then
  4466. return{type="eof",value="",position={
  4467. character=self.character,line=self.line;
  4468. }}
  4469. end
  4470.  
  4471. local char=self.text:sub(self.position,self.position)
  4472.  
  4473. if char=="\""or char=="'" then
  4474. return self:consume_string()
  4475. elseif char == "" or char == "\t" or char == "\n" then
  4476. return self:consume_whitespace()
  4477. elseif self.text:find( "^%.?%d", self.position ) then
  4478. return self:consume_number()
  4479. elseif char:find "%w" or char == "_" then
  4480. return self:consume_identifier()
  4481. else
  4482. return self:consume_symbol()
  4483. end
  4484. end
  4485.  
  4486. function Stream:is_EOF()
  4487. return self:peek().type == "eof"
  4488. end
  4489.  
  4490. function Stream:peek()
  4491. if self.buffer then
  4492. return self.buffer
  4493. end
  4494.  
  4495. local token = self:consume()
  4496. self.buffer = token
  4497. return token
  4498. end
  4499.  
  4500. function Stream:next()
  4501. local token = self:peek()
  4502. self.buffer = nil
  4503. return token
  4504. end
  4505.  
  4506. function Stream:test( type, value )
  4507. local token = self:peek()
  4508. return token.type == type and (value == nil or token.value == value) and token or nil
  4509. end
  4510.  
  4511. function Stream:skip( type, value )
  4512. local token = self:peek()
  4513. return token.type == type and (value == nil or token.value == value) and self:next() or nil
  4514. end
  4515.  
  4516. function Stream:skip_value( type, value )
  4517. local token = self:peek()
  4518. return token.type == type and (value == nil or token.value == value) and self:next().value or nil
  4519. end
  4520.  
  4521.  
  4522.  
  4523.  
  4524. Transition = class.new( "Transition", nil, nil ) {
  4525. duration = 0.4;
  4526. easing_function = nil;
  4527. }
  4528.  
  4529. function Transition:Transition( easing, duration )
  4530. self.easing_function = easing
  4531. self.duration = duration or self.duration
  4532. end
  4533.  
  4534. Transition.none = nil
  4535.  
  4536. Transition.linear = Transition( Easing.linear, 0.4 )
  4537. Transition.linear_slow = Transition( Easing.linear, 0.8 )
  4538. Transition.linear_fast = Transition( Easing.linear, 0.2 )
  4539.  
  4540. Transition.smooth = Transition( Easing.smooth, 0.4 )
  4541. Transition.smooth_slow = Transition( Easing.smooth, 0.8 )
  4542. Transition.smooth_fast = Transition( Easing.smooth, 0.2 )
  4543.  
  4544. Transition.entrance = Transition( Easing.entrance, 0.4 )
  4545. Transition.entrance_slow = Transition( Easing.entrance, 0.8 )
  4546. Transition.entrance_fast = Transition( Easing.entrance, 0.2 )
  4547.  
  4548. Transition.exit = Transition( Easing.exit, 0.4 )
  4549. Transition.exit_slow = Transition( Easing.exit, 0.8 )
  4550. Transition.exit_fast = Transition( Easing.exit, 0.2 )
  4551.  
  4552.  
  4553.  
  4554.  
  4555. Type = class.new( "Type", nil, nil ) {
  4556. name = "";
  4557. }
  4558.  
  4559. UnionType = class.new( "UnionType", Type, nil ) {
  4560. lvalue = nil;
  4561. rvalue = nil;
  4562. }
  4563.  
  4564. ListType = class.new( "ListType", Type, nil ) {
  4565. value = nil;
  4566. }
  4567.  
  4568. TableType = class.new( "TableType", Type, nil ) {
  4569. index = nil;
  4570. value = nil;
  4571. }
  4572.  
  4573. function Type:Type( name )
  4574. self.name = name
  4575. self.meta.__div = self.either
  4576. self.meta.__eq = self.matches
  4577. end
  4578.  
  4579. function UnionType:UnionType( lvalue, rvalue )
  4580. self.lvalue = lvalue
  4581. self.rvalue = rvalue
  4582.  
  4583. return self:Type "Union"
  4584. end
  4585.  
  4586. function ListType:ListType( value )
  4587. self.value = value
  4588.  
  4589. return self:Type "List"
  4590. end
  4591.  
  4592. function TableType:TableType( index, value )
  4593. self.index = index
  4594. self.value = value
  4595.  
  4596. return self:Type "Table"
  4597. end
  4598.  
  4599. function Type:tostring()
  4600. return self.name
  4601. end
  4602.  
  4603. function UnionType:tostring()
  4604. return self.lvalue:tostring() .. " | " .. self.rvalue:tostring()
  4605. end
  4606.  
  4607. function ListType:tostring()
  4608. return self.value:tostring() .. "[]"
  4609. end
  4610.  
  4611. function TableType:tostring()
  4612. return self.value:tostring() .. "{" .. self.index:tostring() .. "}"
  4613. end
  4614.  
  4615. function Type:either( other )
  4616. return UnionType( self, other )
  4617. end
  4618.  
  4619. function Type:matches( type )
  4620. if self:type_of( UnionType ) then
  4621. return self.lvalue:matches( type ) and self.rvalue:matches( type )
  4622. end
  4623.  
  4624. if type:type_of( UnionType ) then
  4625. return self:matches( type.lvalue ) or self:matches( type.rvalue )
  4626. elseif type:type_of( ListType ) then
  4627. return self.name == "List" and self.value:matches( type.value )
  4628. elseif type:type_of( TableType ) then
  4629. return self.name == "Table" and self.value:matches( type.value ) and self.index:matches( type.index )
  4630. elseif type.name == "Any" then
  4631. return true
  4632. else
  4633. return self.name == type.name
  4634. end
  4635. end
  4636.  
  4637. function Type:casts_to( type )
  4638.  
  4639. end
  4640.  
  4641. Type.primitive = {}
  4642. Type.primitive.null = Type "Null"
  4643. Type.primitive.integer = Type "Integer"
  4644. Type.primitive.number = Type "Number"
  4645. Type.primitive.string = Type "String"
  4646. Type.primitive.boolean = Type "Boolean"
  4647. Type.primitive.optional_integer = Type.primitive.integer / Type.primitive.null
  4648. Type.primitive.optional_number = Type.primitive.number / Type.primitive.null
  4649. Type.primitive.optional_string = Type.primitive.string / Type.primitive.null
  4650. Type.primitive.optional_boolean = Type.primitive.boolean / Type.primitive.null
  4651.  
  4652. Type.any = Type "Any"
  4653.  
  4654. Type.sheets = {}
  4655. Type.sheets.colour = Type "colour"
  4656. Type.sheets.alignment = Type "alignment"
  4657. Type.sheets.Sheet = Type "Sheet"
  4658. Type.sheets.optional_Sheet = Type "Sheet" / Type.primitive.null
  4659. Type.sheets.Screen = Type "Screen"
  4660. Type.sheets.Application = Type "Application"
  4661. Type.sheets.Sheet_or_Screen = Type.sheets.Sheet / Type.sheets.Screen
  4662.  
  4663.  
  4664.  
  4665.  
  4666. Typechecking = class.new( "Typechecking", nil, nil ) {
  4667.  
  4668. }
  4669.  
  4670. function Typechecking.check_type( ast, state )
  4671. if ast.type == "self" then
  4672. return ast, state.object:type_of( Sheet ) and Type.sheets.Sheet
  4673. or state.object:type_of( Screen ) and Type.sheets.Screen
  4674. or state.object:type_of( Application ) and Type.sheets.Application
  4675. or error "this really should never happen but just incase here's an error message"
  4676.  
  4677. elseif ast.type == "parent" then
  4678. return ast, state.object:type_of( Sheet ) and Type.sheets.Sheet_or_Screen
  4679. or state.object:type_of( Screen ) and Type.sheets.Application
  4680. or state.object:type_of( Application ) and Type.primitive.null
  4681. or error "this really should never happen but just incase here's another error message"
  4682.  
  4683. elseif ast.type == "call" then
  4684. return ast, error "TODO: implement calls, idk how but you can do this!"
  4685.  
  4686. elseif ast.type == "query" or ast.type == "dynamic query" then
  4687. local src, srctype = Typechecking.check_type( ast.source, state )
  4688.  
  4689. if not (srctype == Type.sheets.Sheet_or_Screen or srctype == Type.sheets.Application) then
  4690. error "TODO: fix this error"
  4691. end
  4692.  
  4693. ast.source = src
  4694.  
  4695. return ast, Type.sheets.Sheet_or_Screen
  4696.  
  4697. elseif ast.type == "string" then
  4698. return ast, Type.primitive.string
  4699.  
  4700. elseif ast.type == "integer" then
  4701. return ast, Type.primitive.integer
  4702.  
  4703. elseif ast.type == "float" then
  4704. return ast, Type.primitive.number
  4705.  
  4706. elseif ast.type == "boolean" then
  4707. return ast, Type.primitive.boolean
  4708.  
  4709. elseif ast.type == "index" then
  4710. return ast, error "TODO: implement indexes, idk how but you can do this!"
  4711.  
  4712. elseif ast.type == "application" then
  4713. return ast, Type.sheets.Application
  4714.  
  4715. elseif ast.type == "identifier" then
  4716. if state.environment[ast.value] then
  4717. return ast, state.environment[ast.value].type
  4718.  
  4719. elseif state.object.values:has( ast.value ) then
  4720. return {
  4721. type = "dotindex";
  4722. value = {
  4723. type = "self";
  4724. };
  4725. index = ast.value;
  4726. }, ValueHandler.properties[ast.value].type
  4727.  
  4728. else
  4729. error "TODO: fix this error"
  4730.  
  4731. end
  4732.  
  4733. elseif ast.type == "unary operator expression" then
  4734. local _ast, type = Typechecking.check_type( ast.value, state )
  4735.  
  4736. ast.value = _ast
  4737.  
  4738. if ast.operator == "#" then
  4739. if not (type == ListType( Type.any ) or type == Type.primitive.string) then
  4740. error "TODO: fix this error"
  4741. end
  4742.  
  4743. type = Type.primitive.integer
  4744. elseif ast.operator == "!" then
  4745. -- any type is fine
  4746. elseif ast.operator == "-" or ast.operator == "+" then
  4747. if not (type == Type.primitive.integer or type == Type.primitive.number) then
  4748. error "TODO: fix this error"
  4749. end
  4750. end
  4751.  
  4752. return ast, type
  4753.  
  4754. elseif ast.type == "dotindex" then
  4755. local _ast, vtype = Typechecking.check_type( ast.value, state )
  4756.  
  4757. ast.value = _ast
  4758.  
  4759. if ValueHandler.properties[ast.index] then
  4760.  
  4761. if vtype == (Type.sheets.Sheet_or_Screen / Type.sheets.Application / Type.primitive.null) then
  4762. return ast, ValueHandler.properties[ast.index].type -- do a check for the index
  4763. else
  4764. error "TODO: fix this error"
  4765. end
  4766. else
  4767. error "TODO: fix this error"
  4768. end
  4769.  
  4770. return ast
  4771.  
  4772. elseif ast.type == "percentage" then
  4773. -- See issue #37
  4774.  
  4775. elseif ast.type == "binary operator expression" then
  4776. local lvalue_ast, lvalue_type = Typechecking.check_type( ast.lvalue, state )
  4777. local rvalue_ast, rvalue_type = Typechecking.check_type( ast.rvalue, state )
  4778.  
  4779. ast.lvalue = lvalue_ast
  4780. ast.rvalue = rvalue_ast
  4781.  
  4782. if ast.operator == "+" then
  4783. if lvalue_type == Type.primitive.string then
  4784. if not (rvalue_type == Type.primitive.string or rvalue_type == Type.primitive.integer or rvalue_type == Type.primitive.number) then
  4785. -- tostring it
  4786. error "TODO: implement this"
  4787. end
  4788.  
  4789. ast.operator = ".."
  4790.  
  4791. return ast, Type.primitive.string
  4792. elseif rvalue_type == Type.primitive.string then
  4793. if not (lvalue_type == Type.primitive.string or lvalue_type == Type.primitive.integer or lvalue_type == Type.primitive.number) then
  4794. -- tostring it
  4795. error "TODO: implement this"
  4796. end
  4797.  
  4798. ast.operator = ".."
  4799. elseif lvalue_type == Type.primitive.integer then
  4800. if rvalue_type == Type.primitive.integer then
  4801. return ast, Type.primitive.integer
  4802. elseif rvalue_type == Type.primitive.number then
  4803. return ast, Type.primitive.number
  4804. else
  4805. error "TODO: fix this error"
  4806. end
  4807. elseif lvalue_type == Type.primitive.number then
  4808. if rvalue_type == Type.primitive.integer or rvalue_type == Type.primitive.number then
  4809. return ast, Type.primitive.number
  4810. else
  4811. error "TODO: fix this error"
  4812. end
  4813. else
  4814. error "TODO: fix this error"
  4815. end
  4816.  
  4817. elseif ast.operator == "-" or ast.operator == "*" or ast.operator == "^" then
  4818. if lvalue_type == Type.primitive.integer then
  4819. if rvalue_type == Type.primitive.integer then
  4820. return ast, Type.primitive.integer
  4821. elseif rvalue_type == Type.primitive.number then
  4822. return ast, Type.primitive.number
  4823. else
  4824. error "TODO: fix this error"
  4825. end
  4826. elseif lvalue_type == Type.primitive.number then
  4827. if rvalue_type == Type.primitive.integer or rvalue_type == Type.primitive.number then
  4828. return ast, Type.primitive.number
  4829. else
  4830. error "TODO: fix this error"
  4831. end
  4832. else
  4833. error "TODO: fix this error"
  4834. end
  4835.  
  4836. elseif ast.operator == "/" then
  4837. if lvalue_type == Type.primitive.integer / Type.primitive.number
  4838. and rvalue_type == Type.primitive.integer / Type.primitive.number then
  4839. return ast, Type.primitive.number
  4840. else
  4841. error "TODO: fix this error"
  4842. end
  4843.  
  4844. elseif ast.operator == "%" then
  4845. if lvalue_type == Type.primitive.integer and rvalue_type == Type.primitive.integer then
  4846. return ast, Type.primitive.number
  4847. else
  4848. error "TODO: fix this error"
  4849. end
  4850.  
  4851. elseif ast.operator == "and" then
  4852. return ast, rvalue_type / Type.primitive.null
  4853.  
  4854. elseif ast.operator == "or" then
  4855. local tr = { lvalue_type }
  4856. local idx = 1
  4857.  
  4858. while tr[idx] do
  4859. local t = tr[idx]
  4860.  
  4861. if t:type_of( UnionType ) then
  4862. if not (t.lvalue == Type.primitive.null) then
  4863. tr[idx] = t.lvalue
  4864. if not (t.rvalue == Type.primitive.null) then
  4865. table.insert( tr, idx, t.rvalue )
  4866. end
  4867. elseif not (t.rvalue == Type.primitive.null) then
  4868. tr[idx] = t.rvalue
  4869. else
  4870. table.remove( tr, idx )
  4871. end
  4872. else
  4873. idx = idx + 1
  4874. end
  4875. end
  4876.  
  4877. local t = tr[1]
  4878.  
  4879. if t then
  4880. for i = 2, #tr do
  4881. t = UnionType( t, tr[i] )
  4882. end
  4883.  
  4884. return ast, t / rvalue_type
  4885. else
  4886. return rvalue_ast, rvalue_type
  4887. end
  4888.  
  4889. elseif ast.operator == ">" or ast.operator == "<" or ast.operator == ">=" or ast.operator == "<=" then
  4890. if lvalue_type == Type.primitive.integer / Type.primitive.number
  4891. and rvalue_type == Type.primitive.integer / Type.primitive.number then
  4892. return Type.primitive.boolean
  4893. else
  4894. error "TODO: fix this error"
  4895. end
  4896.  
  4897. elseif ast.operator == "~=" or ast.operator == "==" then
  4898. return type.primitive.boolean
  4899.  
  4900. end
  4901.  
  4902. elseif ast.type == "tag" then
  4903. local obj, objtype = Typechecking.check_type( ast.value, state )
  4904.  
  4905. ast.value = obj
  4906.  
  4907. if objtype == Type.sheets.Sheet_or_Screen / Type.primitive.null then
  4908. return ast, Type.primitive.boolean
  4909. else
  4910. error "TODO: fix this error"
  4911. end
  4912.  
  4913. end
  4914. end
  4915.  
  4916. function Typechecking.resolve_type( value )
  4917. local t = type( value )
  4918.  
  4919. if t == "number" then
  4920. return value % 1 == 0 and Type.primitive.integer or Type.primitive.number
  4921. elseif t == "boolean" or t == "string" then
  4922. return Type.primitive[t]
  4923. elseif t == "nil" then
  4924. return Type.primitive.null
  4925. -- potentially add tables here
  4926. else
  4927. return Type.any
  4928. end
  4929. end
  4930.  
  4931.  
  4932.  
  4933.  
  4934. local floor = math.floor
  4935. local get_transition_function
  4936. local TRANSITION_FUNCTION_CODE
  4937. local tfcache = {}
  4938. local setf
  4939.  
  4940. ValueHandler = class.new( "ValueHandler", nil, nil ) {
  4941. object = nil;
  4942. lifetimes = {};
  4943. values = {};
  4944. subscriptions = {};
  4945. defaults = {};
  4946. removed_lifetimes = {};
  4947. transitions = {};
  4948. transitions_lookup = {};
  4949. }
  4950.  
  4951. ValueHandler.properties = {}
  4952.  
  4953. function ValueHandler:ValueHandler( object )
  4954. self.object = object
  4955. self.lifetimes = {}
  4956. self.values = {}
  4957. self.subscriptions = {}
  4958. self.defaults = {}
  4959. self.removed_lifetimes = {}
  4960. self.transitions = {}
  4961. self.transitions_lookup = {}
  4962.  
  4963. object.set = setf
  4964. end
  4965.  
  4966. function ValueHandler:add( name, default, options )
  4967. if not ValueHandler.properties[name] then
  4968. error "TODO: fix this error"
  4969. end
  4970.  
  4971. self.object["set_" .. name] = type( options ) == "function" and options or Codegen.dynamic_property_setter( name, options )
  4972. self.object["raw_" .. name] = default
  4973. self.object[name] = default
  4974. self.values[#self.values + 1] = name
  4975. self.defaults[name] = default
  4976. self.lifetimes[name] = {}
  4977.  
  4978. if ValueHandler.properties[name].transitionable then
  4979. self.object["set_" .. name .. "_transition"] = get_transition_function( name )
  4980. self.object[name .. "_transition"] = Transition.none
  4981. end
  4982. end
  4983.  
  4984. function ValueHandler:remove( name )
  4985. self.lifetimes[name] = nil
  4986. self.values[name] = nil
  4987. self.object[name] = nil
  4988. self.object["raw_" .. name] = nil
  4989. self.object["set_" .. name] = nil
  4990. end
  4991.  
  4992. function ValueHandler:has( name )
  4993. return self.lifetimes[name] ~= nil
  4994. end
  4995.  
  4996. function ValueHandler:trigger( name )
  4997. if self.subscriptions[name] then
  4998. for i = #self.subscriptions[name], 1, -1 do
  4999. self.subscriptions[name][i]()
  5000. end
  5001. end
  5002. end
  5003.  
  5004. function ValueHandler:respawn( name )
  5005. local t = self.lifetimes[name]
  5006.  
  5007. for i = #t, 1, -1 do
  5008. local l = t[i]
  5009. t[i] = nil
  5010. if l[1] == "value" then
  5011. l[2].values:unsubscribe( l[3], l[4] )
  5012. elseif l[1] == "query" then
  5013. l[2]:unsubscribe( l[3], l[4] )
  5014. elseif l[1] == "tag" then
  5015. l[2]:unsubscribe_from_tag( l[3], l[4] )
  5016. end
  5017. end
  5018.  
  5019. self.lifetimes[name] = {}
  5020. end
  5021.  
  5022. function ValueHandler:subscribe( name, lifetime, callback )
  5023. self.subscriptions[name] = self.subscriptions[name] or {}
  5024. lifetime[#lifetime + 1] = { "value", self.object, name, callback }
  5025.  
  5026. local t = self.subscriptions[name]
  5027.  
  5028. t[#t + 1] = callback
  5029.  
  5030. return callback
  5031. end
  5032.  
  5033. function ValueHandler:unsubscribe( name, callback )
  5034. if self.subscriptions[name] then
  5035. for i = #self.subscriptions[name], 1, -1 do
  5036. if self.subscriptions[name][i] == callback then
  5037. table.remove( self.subscriptions[name], i )
  5038. return callback
  5039. end
  5040. end
  5041. end
  5042. end
  5043.  
  5044. function ValueHandler:child_removed()
  5045. for k, v in pairs( self.lifetimes ) do
  5046. self.removed_lifetimes[k] = v
  5047. self:respawn( k )
  5048. end
  5049. end
  5050.  
  5051. function ValueHandler:child_inserted()
  5052. for k, v in pairs( self.removed_lifetimes ) do
  5053. local lifetime = self.lifetimes[k]
  5054.  
  5055. for i = 1, #v do
  5056. if v[i][1] == "value" then
  5057. v[i][2].values:subscribe( v[i][3], lifetime, v[i][4] )
  5058. elseif v[i][1] == "query" then
  5059. v[i][2]:subscribe( v[i][3], lifetime, v[i][4] )
  5060. end
  5061. v[i][4]()
  5062. end
  5063. end
  5064.  
  5065. self.removed_lifetimes = {}
  5066. end
  5067.  
  5068. function ValueHandler:transition( property, final, transition, custom_update )
  5069. local index = self.transitions_lookup[property] or #self.transitions + 1
  5070. local floored = false -- TODO: make this respect the property
  5071. local ptype = ValueHandler.properties[property].type
  5072.  
  5073. if ptype == Type.primitive.integer then
  5074. floored = true
  5075. elseif ptype ~= Type.primitive.number then
  5076. Exception.throw( Exception( "PropertyTransitionException", "Cannot animate non-number property '" .. property .. "'" ) ) -- TODO: make custom exception for this
  5077. end
  5078.  
  5079. final = floored and floor( final + 0.5 ) or final
  5080.  
  5081. if transition ~= Transition.none and self.object.application then
  5082. self.transitions_lookup[property] = index
  5083. self.transitions[index] = {
  5084. property = property;
  5085. initial = self.object[property];
  5086. final = final;
  5087. diff = final - self.object[property];
  5088. duration = transition.duration;
  5089. clock = 0;
  5090. easing = transition.easing_function;
  5091. floored = floored;
  5092. change = ValueHandler.properties[property].change;
  5093. custom_update = custom_update;
  5094. }
  5095. else
  5096. if self.object[property] ~= final then
  5097. self.object[property] = final
  5098.  
  5099. if ValueHandler.properties[property].change == "self" then
  5100. self.object:set_changed()
  5101. elseif ValueHandler.properties[property].change == "parent" and self.object.parent then
  5102. self.object.parent:set_changed()
  5103. end
  5104.  
  5105. if custom_update then
  5106. custom_update( self.object )
  5107. end
  5108.  
  5109. self:trigger( property )
  5110. end
  5111. end
  5112. end
  5113.  
  5114. function ValueHandler:update( dt )
  5115. for i = #self.transitions, 1, -1 do
  5116. local trans = self.transitions[i]
  5117. trans.clock = trans.clock + dt
  5118.  
  5119. if trans.clock >= trans.duration then
  5120. self.object[trans.property] = trans.final
  5121. table.remove( self.transitions, i )
  5122. self.transitions_lookup[trans.property] = nil
  5123. else
  5124. local eased = trans.easing( trans.initial, trans.diff, trans.clock / trans.duration )
  5125. self.object[trans.property] = trans.floored and floor( eased + 0.5 ) or eased
  5126. end
  5127.  
  5128. if trans.change == "self" then
  5129. self.object:set_changed()
  5130. elseif trans.change == "parent" and self.object.parent then
  5131. self.object.parent:set_changed()
  5132. end
  5133.  
  5134. if trans.custom_update then
  5135. trans.custom_update( self.object )
  5136. end
  5137.  
  5138. self:trigger( trans.property )
  5139. end
  5140. end
  5141.  
  5142. ValueHandler.properties.x = { type = Type.primitive.integer, change = "parent", transitionable = true }
  5143. ValueHandler.properties.y = { type = Type.primitive.integer, change = "parent", transitionable = true }
  5144. ValueHandler.properties.z = { type = Type.primitive.integer, change = "parent", transitionable = true }
  5145.  
  5146. ValueHandler.properties.x_offset = { type = Type.primitive.integer, change = "self", transitionable = true }
  5147. ValueHandler.properties.y_offset = { type = Type.primitive.integer, change = "self", transitionable = true }
  5148.  
  5149. ValueHandler.properties.width = { type = Type.primitive.integer, change = "self", transitionable = true }
  5150. ValueHandler.properties.height = { type = Type.primitive.integer, change = "self", transitionable = true }
  5151.  
  5152. ValueHandler.properties.text = { type = Type.primitive.string, change = "self", transitionable = false }
  5153.  
  5154. ValueHandler.properties.horizontal_alignment = { type = Type.sheets.alignment, change = "self", transitionable = false }
  5155. ValueHandler.properties.vertical_alignment = { type = Type.sheets.alignment, change = "self", transitionable = false }
  5156.  
  5157. ValueHandler.properties.colour = { type = Type.sheets.colour, change = "self", transitionable = false }
  5158. ValueHandler.properties.text_colour = { type = Type.sheets.colour, change = "self", transitionable = false }
  5159. ValueHandler.properties.active_colour = { type = Type.sheets.colour, change = "self", transitionable = false }
  5160.  
  5161. ValueHandler.properties.parent = { type = Type.sheets.optional_Sheet, change = "parent", transitionable = false }
  5162.  
  5163. function get_transition_function( name )
  5164. if not tfcache[name] then
  5165. tfcache[name] = (load or loadstring)( TRANSITION_FUNCTION_CODE:gsub( "PROPERTY", name ) )()
  5166. end
  5167.  
  5168. return tfcache[name]
  5169. end
  5170.  
  5171. function setf( self, t )
  5172. for k, v in pairs( t ) do
  5173. if self["set_" .. k] then
  5174. self["set_" .. k]( self, v )
  5175. else
  5176. -- TODO: error or just ignore?
  5177. end
  5178. end
  5179.  
  5180. return self
  5181. end
  5182.  
  5183. TRANSITION_FUNCTION_CODE = [[
  5184. return function( self, value )
  5185. self.PROPERTY_transition = value
  5186. return self
  5187. end]]
  5188.  
  5189.  
  5190.  
  5191.  
  5192.  
  5193. local function exception_handler( e )
  5194. return error( tostring( e ), 0 )
  5195. end
  5196.  
  5197. local handle_event
  5198.  
  5199. Application = class.new( "Application", nil, IQueryable, ITimer ) {
  5200. name = "UnNamed Application";
  5201. path = "";
  5202.  
  5203. terminateable = true;
  5204. running = true;
  5205.  
  5206. screen = nil;
  5207.  
  5208. -- internal
  5209. screens = {};
  5210.  
  5211. resource_loaders = {};
  5212. extensions = {};
  5213.  
  5214.  
  5215.  
  5216.  
  5217.  
  5218. mouse = nil;
  5219. keys = {};
  5220. changed = false;
  5221. }
  5222.  
  5223. function Application:Application( name, path )
  5224. self.name = name
  5225. self.path = path or name
  5226.  
  5227. self.screens = {}
  5228. self.resource_loaders = {}
  5229. self.extensions = {}
  5230.  
  5231.  
  5232.  
  5233. self.keys = {}
  5234.  
  5235. self:ICollatedChildren()
  5236. self:IQueryable()
  5237. self:ITimer()
  5238.  
  5239. self.screens[1] = Screen( self, term.getSize() ):add_terminal( term )
  5240. self.screen = self.screens[1]
  5241. end
  5242.  
  5243. function Application:register_resource_loader( type, loader )
  5244. parameters.check( 2, "type", "string", type, "loader", "function", loader )
  5245.  
  5246. self.resource_loaders[type] = loader
  5247. end
  5248.  
  5249. function Application:unregister_resource_loader( type )
  5250. parameters.check( 1, "type", "string", type )
  5251. self.resource_loaders[type] = nil
  5252. end
  5253.  
  5254. function Application:register_file_extension( extension, type )
  5255. parameters.check( 2, "extension", "string", extension, "type", "string", type )
  5256.  
  5257. self.extensions[extension] = type
  5258. end
  5259.  
  5260. function Application:unregister_file_extension( extension )
  5261. parameters.check( 1, "extension", "string", extension )
  5262.  
  5263. self.extensions[extension] = nil
  5264. end
  5265.  
  5266. function Application:load_resource( resource, type, ... )
  5267. parameters.check( 2, "resource", "string", resource, "type", "string", type or "" )
  5268.  
  5269. if not type then
  5270. type = self.extensions[resource:match( "%.(%w+)$" ) or "txt"] or "text.plain"
  5271. end
  5272.  
  5273. if self.resource_loaders[type] then
  5274.  
  5275. local h = fs.open( fs.combine( self.path, resource ), "r" ) or fs.open( resource, "r" )
  5276. if h then
  5277.  
  5278. local content = h.readAll()
  5279. h.close()
  5280.  
  5281. return self.resource_loaders[type]( self, resource, content, ... )
  5282.  
  5283. else
  5284. Exception.throw( ResourceLoadException, "Failed to open file'" .. resource .. "':not found under'/''or'" .. self.path .. "'", 2 )
  5285. end
  5286.  
  5287. else
  5288. Exception.throw( ResourceLoadException, "No loader for resource type'" .. type .. "'", 2 )
  5289. end
  5290. end
  5291.  
  5292.  
  5293.  
  5294.  
  5295.  
  5296.  
  5297.  
  5298.  
  5299.  
  5300.  
  5301.  
  5302. function Application:is_key_pressed( key )
  5303. parameters.check( 1, "key", "string", key )
  5304.  
  5305. return self.keys[key] ~= nil
  5306. end
  5307.  
  5308. function Application:stop()
  5309. self.running = false
  5310. return self
  5311. end
  5312.  
  5313. function Application:add_screen()
  5314. local screen = Screen( self, term.get_size() )
  5315.  
  5316. self.screens[#self.screens + 1] = screen
  5317.  
  5318. return screen
  5319. end
  5320.  
  5321. function Application:remove_screen( screen )
  5322. parameters.check( 1, "screen", Screen, screen )
  5323.  
  5324. for i = #self.screens, 1, -1 do
  5325. if self.screens[i] == screen then
  5326. return table.remove( self.screens, i )
  5327. end
  5328. end
  5329. end
  5330.  
  5331. function Application:child_value_changed( child )
  5332. return self.query_tracker:update( "child-changed", child )
  5333. end
  5334.  
  5335. function Application:update_collated( mode, child, data )
  5336. local collated = self.collated_children
  5337.  
  5338. if mode == "child-added" then
  5339. if data:type_of( Screen ) then
  5340. local v = data
  5341.  
  5342. data = nil
  5343.  
  5344. for i = 1, #self.screens do
  5345. if self.screens[i] == v then
  5346. repeat
  5347. i = i + 1
  5348. until not self.screens[i] or #self.screens[i].collated_children > 0
  5349.  
  5350. if self.screens[i] then
  5351. data = self.screens[i].collated_children[1]
  5352. end
  5353.  
  5354. break
  5355. end
  5356. end
  5357. end
  5358.  
  5359. if data then
  5360. for i = #collated, 1, -1 do
  5361. if collated[i] == data then
  5362. if child:implements( ICollatedChildren ) then
  5363. i = i - 1
  5364.  
  5365. for n = 1, #child.collated_children do
  5366. table.insert( collated, i + n, child.collated_children[n] )
  5367. end
  5368.  
  5369. table.insert( collated, i + #child.collated_children + 1, child )
  5370. else
  5371. table.insert( collated, i, child )
  5372. end
  5373. end
  5374. end
  5375. else
  5376. if child:implements( ICollatedChildren ) then
  5377. for i = 1, #child.collated_children do
  5378. collated[#collated + 1] = child.collated_children[i]
  5379. end
  5380. end
  5381.  
  5382. collated[#collated + 1] = child
  5383. end
  5384. elseif mode == "child-removed" then
  5385. local open, close = child:implements( ICollatedChildren ) and child.collated_children[1] or child, child
  5386. local removing = false
  5387.  
  5388. for i = #collated, 1, -1 do
  5389. if collated[i] == close then removing = true end
  5390. local brk = collated[i] == open
  5391. if removing then table.remove( collated, i ) end
  5392. if brk then break end
  5393. end
  5394. end
  5395.  
  5396. self.query_tracker:update( mode, child )
  5397. end
  5398.  
  5399. function Application:event( event, ... )
  5400. local params = { ... }
  5401.  
  5402. if event == "timer" and self:update_timer( ... ) then
  5403. return
  5404. end
  5405.  
  5406. return handle_event( self, event, params, ... )
  5407. end
  5408.  
  5409. function Application:draw()
  5410.  
  5411. if self.changed then
  5412. for i = 1, #self.screens do
  5413. self.screens[i]:draw()
  5414. end
  5415. self.changed = false
  5416. end
  5417.  
  5418. end
  5419.  
  5420. function Application:update()
  5421. local dt = self:step_timer():get_timer_delta()
  5422.  
  5423. for i = 1, #self.screens do
  5424. self.screens[i]:update( dt )
  5425. end
  5426.  
  5427. if self.on_update then
  5428. self:on_update( dt )
  5429. end
  5430. end
  5431.  
  5432. function Application:load()
  5433. self.changed = true
  5434.  
  5435. if self.on_load then
  5436. return self:on_load()
  5437. end
  5438. end
  5439.  
  5440. function Application:run()
  5441.  
  5442. Exception.try (function()
  5443. self:load()
  5444. local t = os.startTimer( 0 ) -- updating timer
  5445. while self.running do
  5446. local event = { coroutine.yield() }
  5447. if event[1] == "timer" and event[2] == t then
  5448. t = os.startTimer( .05 )
  5449. elseif event[1] == "terminate" and self.terminateable then
  5450. self:stop()
  5451. else
  5452. self:event( unpack( event ) )
  5453. end
  5454. self:update()
  5455. self:draw()
  5456. end
  5457.  
  5458. end) {
  5459. Exception.default (exception_handler);
  5460. }
  5461.  
  5462. end
  5463.  
  5464. function handle_event( self, event, params, ... )
  5465. local screens = {}
  5466.  
  5467. for i = 1, #self.screens do
  5468. screens[i] = self.screens[i]
  5469. end
  5470.  
  5471. if event == "mouse_click" then
  5472. self.mouse = {
  5473. x = params[2] - 1, y = params[3] - 1;
  5474. down = true, button = params[1];
  5475. timer = os.startTimer( 1 ), time = os.clock(), moved = false;
  5476. }
  5477.  
  5478. local e = MouseEvent( 0, params[2] - 1, params[3] - 1, params[1], true )
  5479.  
  5480. for i = #screens, 1, -1 do
  5481. if screens[i]:gets_term_events() then
  5482. screens[i]:handle( e )
  5483. end
  5484. end
  5485.  
  5486. elseif event == "mouse_up" then
  5487. local e = MouseEvent( 1, params[2] - 1, params[3] - 1, params[1], true )
  5488.  
  5489. for i = #screens, 1, -1 do
  5490. if screens[i]:gets_term_events() then
  5491. screens[i]:handle( e )
  5492. end
  5493. end
  5494.  
  5495. self.mouse.down = false
  5496. os.cancelTimer( self.mouse.timer )
  5497.  
  5498. if not self.mouse.moved and os.clock() - self.mouse.time < 1 and params[1] == self.mouse.button then
  5499. local e = MouseEvent( 2, params[2] - 1, params[3] - 1, params[1], true )
  5500.  
  5501. for i = #screens, 1, -1 do
  5502. if screens[i]:gets_term_events() then
  5503. screens[i]:handle( e )
  5504. end
  5505. end
  5506. end
  5507.  
  5508. elseif event == "mouse_drag" then
  5509. local e = MouseEvent( 4, params[2] - 1, params[3] - 1, params[1], true )
  5510.  
  5511. for i = #screens, 1, -1 do
  5512. if screens[i]:gets_term_events() then
  5513. screens[i]:handle( e )
  5514. end
  5515. end
  5516.  
  5517. self.mouse.moved = true
  5518. os.cancelTimer( self.mouse.timer )
  5519.  
  5520. elseif event == "mouse_scroll" then
  5521. local e = MouseEvent( 5, params[2] - 1, params[3] - 1, params[1], true )
  5522.  
  5523. for i = #screens, 1, -1 do
  5524. if screens[i]:gets_term_events() then
  5525. screens[i]:handle( e )
  5526. end
  5527. end
  5528.  
  5529. elseif event == "monitor_touch" then
  5530. local events = {
  5531. MouseEvent( 0, params[2] - 1, params[3] - 1, 1 );
  5532. MouseEvent( 1, params[2] - 1, params[3] - 1, 1 );
  5533. MouseEvent( 2, params[2] - 1, params[3] - 1, 1 );
  5534. }
  5535.  
  5536. for i = 1, #screens do
  5537. if screens[i]:uses_monitor( params[1] ) then
  5538. for n = 1, #events do
  5539. screens[i]:handle( events[n] )
  5540. end
  5541. end
  5542. end
  5543.  
  5544. elseif event == "chatbox_something" then
  5545. -- TODO: implement this
  5546. -- handle( TextEvent( 10, params[1] ) )
  5547.  
  5548. elseif event == "char" then
  5549. local e = TextEvent( 9, params[1] )
  5550.  
  5551. for i = #screens, 1, -1 do
  5552. screens[i]:handle( e )
  5553. end
  5554.  
  5555. elseif event == "paste" then
  5556. local e
  5557. if self.keys.leftShift or self.keys.rightShift then -- TODO: why the left_ctrl/right_ctrl?
  5558. e = KeyboardEvent( 7, keys.v, { left_ctrl = true, right_ctrl = true } )
  5559. else
  5560. e = TextEvent( 11, params[1] )
  5561. end
  5562.  
  5563. for i = #screens, 1, -1 do
  5564. screens[i]:handle( e )
  5565. end
  5566.  
  5567. elseif event == "key" then
  5568. self.keys[keys.getName( params[1] ) or params[1]] = os.clock()
  5569. local e = KeyboardEvent( 7, params[1], self.keys )
  5570.  
  5571. for i = #screens, 1, -1 do
  5572. screens[i]:handle( e )
  5573. end
  5574.  
  5575. elseif event == "key_up" then
  5576. self.keys[keys.getName( params[1] ) or params[1]] = nil
  5577. local e = KeyboardEvent( 8, params[1], self.keys )
  5578.  
  5579. for i = #screens, 1, -1 do
  5580. screens[i]:handle( e )
  5581. end
  5582.  
  5583. elseif event == "term_resize" then
  5584. local width, height = term.getSize()
  5585.  
  5586. for i = 1, #screens do
  5587. if screens[i].terminals[1] == term then
  5588. screens[i]:set_width( width )
  5589. screens[i]:set_height( height )
  5590. end
  5591. end
  5592.  
  5593. elseif event == "timer" and self.mouse and params[1] == self.mouse.timer then
  5594. local e = MouseEvent( 3, self.mouse.x, self.mouse.y, self.mouse.button, true )
  5595.  
  5596. for i = #screens, 1, -1 do
  5597. if screens[i]:gets_term_events() then
  5598. screens[i]:handle( e )
  5599. end
  5600. end
  5601.  
  5602. else
  5603. local ev = MiscEvent( event, ... )
  5604.  
  5605. for i = #screens, 1, -1 do
  5606. screens[i]:handle( ev )
  5607. end
  5608.  
  5609. if not ev.handled then
  5610.  
  5611.  
  5612.  
  5613.  
  5614.  
  5615.  
  5616.  
  5617.  
  5618.  
  5619. end
  5620. end
  5621. end
  5622.  
  5623.  
  5624.  
  5625.  
  5626. Screen = class.new( "Screen", nil, IChildContainer, ITagged, ISize ) {
  5627. parent = nil;
  5628.  
  5629. -- internal
  5630. terminals = {};
  5631. monitors = {};
  5632.  
  5633. surface = nil;
  5634. changed = true;
  5635. values = nil;
  5636. }
  5637.  
  5638. function Screen:Screen( application, width, height )
  5639. self.parent = application
  5640. self.terminals = {}
  5641. self.monitors = {}
  5642. self.surface = surface.create( 0, 0 )
  5643. self.application = application
  5644. self.values = ValueHandler( self )
  5645.  
  5646. self:ICollatedChildren()
  5647. self:IQueryable()
  5648. self:IChildContainer()
  5649. self:ITagged()
  5650. self:ISize()
  5651.  
  5652. self:set_width( width )
  5653. self:set_height( height )
  5654. end
  5655.  
  5656. function Screen:gets_term_events()
  5657. for i = 1, #self.terminals do
  5658. if self.terminals[i] == term then
  5659. return true
  5660. end
  5661. end
  5662. return false
  5663. end
  5664.  
  5665. function Screen:set_changed( state )
  5666. self.changed = state ~= false
  5667. if state ~= false then -- must have a parent Application
  5668. self.parent.changed = true
  5669. end
  5670. return self
  5671. end
  5672.  
  5673. function Screen:add_monitor( side )
  5674. parameters.check( 1, "side", "string", side )
  5675.  
  5676. if peripheral.getType( side ) ~= "monitor" then
  5677. throw( IncorrectParameterException, "expected monitor on side'" .. side .. "',got" .. peripheral.getType( side ), 2 )
  5678. end
  5679.  
  5680. local mon = peripheral.wrap( side )
  5681. self.monitors[side] = mon
  5682.  
  5683. return self:add_terminal( mon )
  5684. end
  5685.  
  5686. function Screen:remove_monitor( side )
  5687. parameters.check( 1, "side", "string", side )
  5688.  
  5689. local mon = self.monitors[side]
  5690. if mon then
  5691. self.monitors[side] = nil
  5692. self:remove_terminal( mon )
  5693. end
  5694.  
  5695. return self
  5696. end
  5697.  
  5698. function Screen:uses_monitor( side )
  5699. return self.monitors[side] ~= nil
  5700. end
  5701.  
  5702. function Screen:add_terminal( t )
  5703. parameters.check( 1, "terminal", "table", t )
  5704.  
  5705. self.terminals[#self.terminals + 1] = t
  5706. self.surface:clear()
  5707.  
  5708. return self:set_changed()
  5709. end
  5710.  
  5711. function Screen:remove_terminal( t )
  5712. parameters.check( 1, "terminal", "table", t )
  5713.  
  5714. for i = #self.terminals, 1, -1 do
  5715. if self.terminals[i] == t then
  5716. self:set_changed()
  5717. return table.remove( self.terminals, i )
  5718. end
  5719. end
  5720.  
  5721. return self
  5722. end
  5723.  
  5724. function Screen:draw()
  5725. if self.changed then
  5726.  
  5727. local surface = self.surface
  5728. local children = {}
  5729. local cx, cy, cc
  5730.  
  5731. surface:clear( 1 )
  5732.  
  5733. for i = 1, #self.children do
  5734. children[i] = self.children[i]
  5735. end
  5736.  
  5737. for i = 1, #children do
  5738. local child = children[i]
  5739.  
  5740. if child:is_visible() then
  5741. child:draw( self.surface, child.x, child.y )
  5742.  
  5743. if child.cursor_active then
  5744. cx, cy, cc = child.x + child.cursor_x, child.y + child.cursor_y, child.cursor_colour
  5745. end
  5746. end
  5747. end
  5748.  
  5749. for i = 1, #self.terminals do
  5750. surface:output( self.terminals[i] )
  5751. end
  5752.  
  5753. self.changed = false
  5754. for i = 1, #self.terminals do
  5755. if cx then
  5756. self.terminals[i].setCursorPos( cx + 1, cy + 1 )
  5757. self.terminals[i].setTextColour( cc )
  5758. self.terminals[i].setCursorBlink( true )
  5759. else
  5760. self.terminals[i].setCursorBlink( false )
  5761. end
  5762. end
  5763. end
  5764. end
  5765.  
  5766. function Screen:handle( event )
  5767. local c = {}
  5768. local children = self.children
  5769. for i = 1, #children do
  5770. c[i] = children[i]
  5771. end
  5772.  
  5773. if event:type_of( MouseEvent ) then
  5774. local within = event:is_within_area( 0, 0, self.width, self.height )
  5775. for i = #c, 1, -1 do
  5776. c[i]:handle( event:clone( c[i].x, c[i].y, within ) )
  5777. end
  5778. else
  5779. for i = #c, 1, -1 do
  5780. c[i]:handle( event )
  5781. end
  5782. end
  5783. end
  5784.  
  5785. function Screen:update( dt )
  5786. local children = {}
  5787.  
  5788. self.values:update( dt )
  5789.  
  5790. for i = 1, #self.children do
  5791. children[i] = self.children[i]
  5792. end
  5793.  
  5794. for i = 1, #children do
  5795. children[i]:update( dt )
  5796. end
  5797. end
  5798.  
  5799.  
  5800.  
  5801.  
  5802. Sheet = class.new( "Sheet", nil, ITagged, ISize ) {
  5803. x = 0;
  5804. y = 0;
  5805. z = 0;
  5806.  
  5807. style = nil;
  5808.  
  5809. parent = nil;
  5810.  
  5811. -- internal
  5812. changed = true;
  5813. cursor_x = 0;
  5814. cursor_y = 0;
  5815. cursor_colour = 0;
  5816. cursor_active = false;
  5817. handles_keyboard = false;
  5818. handles_text = false;
  5819. values = nil;
  5820. }
  5821.  
  5822. function Sheet:Sheet( x, y, width, height )
  5823. if x ~= nil then self:set_x( x ) end
  5824. if y ~= nil then self:set_y( y ) end
  5825. if width ~= nil then self:set_width( width ) end
  5826. if height ~= nil then self:set_height( height ) end
  5827. end
  5828.  
  5829. function Sheet:initialise()
  5830. self.values = ValueHandler( self )
  5831.  
  5832. self:ITagged()
  5833. self:ISize()
  5834.  
  5835. self.values:add( "x", 0 )
  5836. self.values:add( "y", 0 )
  5837. self.values:add( "z", 0, { custom_update_code = "if self.parent then self.parent:reposition_child_z_index(self)end" } )
  5838. self.values:add( "parent", nil, function( self, parent )
  5839. if parent and not class.type_of( parent, Sheet ) and not class.type_of( parent, Screen ) then
  5840. Exception.throw( IncorrectParameterException( "expected Sheet or Screen parent,got" .. class.type( parent ), 2 ) )
  5841. end
  5842.  
  5843. if parent then
  5844. return parent:add_child( self )
  5845. else
  5846. return self:remove()
  5847. end
  5848. end )
  5849. end
  5850.  
  5851. function Sheet:remove()
  5852. if self.parent then
  5853. return self.parent:remove_child( self )
  5854. end
  5855. end
  5856.  
  5857. function Sheet:is_visible()
  5858. return self.parent and self.parent:is_child_visible( self )
  5859. end
  5860.  
  5861. function Sheet:bring_to_front()
  5862. if self.parent then
  5863. return self:set_parent( self.parent ) -- TODO: improve this
  5864. end
  5865. return self
  5866. end
  5867.  
  5868. function Sheet:set_changed( state )
  5869. self.changed = state ~= false
  5870. if state ~= false and self.parent and not self.parent.changed then -- TODO: why not self.parent.changed?
  5871. self.parent:set_changed()
  5872. end
  5873. return self
  5874. end
  5875.  
  5876. function Sheet:set_cursor_blink( x, y, colour )
  5877. colour = colour or 128
  5878.  
  5879. parameters.check( 3, "x", "number", x, "y", "number", y, "colour", "number", colour )
  5880.  
  5881. self.cursor_active = true
  5882. self.cursor_x = x
  5883. self.cursor_y = y
  5884. self.cursor_colour = colour
  5885.  
  5886. return self
  5887. end
  5888.  
  5889. function Sheet:reset_cursor_blink()
  5890. self.cursor_active = false
  5891. return self
  5892. end
  5893.  
  5894. function Sheet:tostring()
  5895. return "[Instance]" .. self.class:type() .. "" .. tostring( self.id )
  5896. end
  5897.  
  5898. function Sheet:update( dt )
  5899. self.values:update( dt )
  5900.  
  5901. if self.on_update then
  5902. self:on_update( dt )
  5903. end
  5904. end
  5905.  
  5906. function Sheet:draw( surface, x, y )
  5907. self.changed = false
  5908. end
  5909.  
  5910. function Sheet:handle( event )
  5911. if event:type_of( MouseEvent ) then
  5912. if event:is( 6 ) and event:is_within_area( 0, 0, self.width, self.height ) and event.within then
  5913. event.button[#event.button + 1] = self
  5914. end
  5915. self:on_mouse_event( event )
  5916. elseif event:type_of( KeyboardEvent ) and self.handles_keyboard and self.on_keyboard_event then
  5917. self:on_keyboard_event( event )
  5918. elseif event:type_of( TextEvent ) and self.handles_text and self.on_text_event then
  5919. self:on_text_event( event )
  5920. end
  5921. end
  5922.  
  5923. function Sheet:on_mouse_event( event )
  5924. if not event.handled and event:is_within_area( 0, 0, self.width, self.height ) and event.within then
  5925. if event:is( 0 ) then
  5926. return event:handle( self )
  5927. end
  5928. end
  5929. end
  5930.  
  5931.  
  5932.  
  5933.  
  5934.  
  5935.  
  5936. Thread = class.new( "Thread", nil, nil ) {
  5937. running = true;
  5938.  
  5939. f = nil;
  5940. co = nil;
  5941. filter = nil;
  5942. }
  5943.  
  5944. function Thread:Thread( f, ... )
  5945. if type( f ) == "string" then
  5946. f = load( f )
  5947. elseif type( f ) ~= "function" then
  5948. parameters.check( 1, "f", "function/string", f )
  5949. end
  5950.  
  5951. self.f = f
  5952. self.co = coroutine.create( f )
  5953.  
  5954. self:resume( ... )
  5955. end
  5956.  
  5957. function Thread:stop()
  5958. self.running = false
  5959. end
  5960.  
  5961. function Thread:restart()
  5962. self.running = true
  5963. self.co = coroutine.create( self.f )
  5964. end
  5965.  
  5966. function Thread:resume( event, ... )
  5967. if not self.running or (self.filter ~= nil and event ~= self.filter) then
  5968. return
  5969. end
  5970.  
  5971. local ok, data = coroutine.resume( self.co, event, ... )
  5972.  
  5973. if ok then
  5974. if coroutine.status( self.co ) == "dead" then
  5975. self.running = false
  5976. end
  5977.  
  5978. self.filter = data
  5979. else
  5980. if data == "SHEETS_EXCEPTION\nPut code in a try block to catch the exception." then
  5981. return Exception.throw( Exception.thrown() )
  5982. end
  5983.  
  5984. return Exception.throw( ThreadRuntimeException, data, 0 )
  5985. end
  5986. end
  5987.  
  5988.  
  5989.  
  5990.  
  5991.  
  5992.  
  5993. -- needs to update to new exception system
  5994.  
  5995. Container = class.new( "Container", Sheet, IChildContainer, IColoured ) {
  5996. colour = nil;
  5997. x_offset = 0;
  5998. y_offset = 0;
  5999.  
  6000. on_pre_draw = nil;
  6001. on_post_draw = nil;
  6002. }
  6003.  
  6004. function Container:Container( x, y, w, h )
  6005. self:initialise()
  6006. self:ICollatedChildren()
  6007. self:IQueryable()
  6008. self:IChildContainer()
  6009. self:IColoured()
  6010.  
  6011. self.values:add( "x_offset", 0 )
  6012. self.values:add( "y_offset", 0 )
  6013.  
  6014. return self:Sheet( x, y, w, h )
  6015. end
  6016.  
  6017. function Container:update( dt )
  6018. local children = self:get_children()
  6019.  
  6020. self.values:update( dt )
  6021.  
  6022. if self.on_update then
  6023. self:on_update( dt )
  6024. end
  6025.  
  6026. for i = #children, 1, -1 do
  6027. children[i]:update( dt )
  6028. end
  6029. end
  6030.  
  6031. function Container:draw( surface, x, y )
  6032. local children = self.children
  6033. local cx, cy, cc
  6034. local x_offset, y_offset = self.x_offset, self.y_offset
  6035.  
  6036. self:reset_cursor_blink()
  6037. surface:fillRect( x, y, self.width, self.height, self.colour )
  6038.  
  6039. if self.on_pre_draw then
  6040. self:on_pre_draw()
  6041. end
  6042.  
  6043. for i = 1, #children do
  6044. local child = children[i]
  6045. if child:is_visible() then
  6046. child:draw( surface, x + child.x + x_offset, y + child.y + y_offset )
  6047.  
  6048. if child.cursor_active then
  6049. cx, cy, cc = child.x + child.cursor_x, child.y + child.cursor_y, child.cursor_colour
  6050. end
  6051. end
  6052. end
  6053.  
  6054. if cx then
  6055. self:set_cursor_blink( cx, cy, cc )
  6056. end
  6057.  
  6058. if self.on_post_draw then
  6059. self:on_post_draw()
  6060. end
  6061.  
  6062. self.changed = false
  6063. end
  6064.  
  6065. function Container:handle( event )
  6066. local children = self:get_children()
  6067. local x_offset, y_offset = self.x_offset, self.y_offset
  6068.  
  6069. if event:type_of( MouseEvent ) then
  6070. local within = event:is_within_area( 0, 0, self.width, self.height )
  6071. for i = #children, 1, -1 do
  6072. children[i]:handle( event:clone( children[i].x + x_offset, children[i].y + y_offset, within ) )
  6073. end
  6074. else
  6075. for i = #children, 1, -1 do
  6076. children[i]:handle( event )
  6077. end
  6078. end
  6079.  
  6080. if event:type_of( MouseEvent ) then
  6081. if event:is( 6 ) and event:is_within_area( 0, 0, self.width, self.height ) and event.within then
  6082. event.button[#event.button + 1] = self
  6083. end
  6084. self:on_mouse_event( event )
  6085. elseif event:type_of( KeyboardEvent ) and self.handles_keyboard and self.on_keyboard_event then
  6086. self:on_keyboard_event( event )
  6087. elseif event:type_of( TextEvent ) and self.handles_text and self.on_text_event then
  6088. self:on_text_event( event )
  6089. end
  6090. end
  6091.  
  6092.  
  6093.  
  6094.  
  6095.  
  6096.  
  6097. local wrapline, wrap
  6098.  
  6099. IHasText = class.new_interface( "IHasText", nil ) {
  6100. text = "";
  6101. text_lines = nil;
  6102. horizontal_alignment = 0;
  6103. vertical_alignment = 3;
  6104. text_colour = 1;
  6105. }
  6106.  
  6107. function IHasText:IHasText()
  6108. local function wrap()
  6109. self:wrap_text()
  6110. self:set_changed()
  6111. end
  6112.  
  6113. self.values:add( "text", "" )
  6114. self.values:add( "text_colour", 1 )
  6115. self.values:add( "horizontal_alignment", 0 )
  6116. self.values:add( "vertical_alignment", 3 )
  6117. self.values:subscribe( "width", {}, wrap )
  6118. self.values:subscribe( "text", {}, wrap )
  6119. end
  6120.  
  6121. function IHasText:auto_height()
  6122. if not self.text_lines then
  6123. self:wrap_text( true )
  6124. end
  6125.  
  6126. return self:set_height( #self.text_lines )
  6127. end
  6128.  
  6129. function IHasText:wrap_text( ignore_height )
  6130. self.text_lines = wrap( self.text, self.width, not ignore_height and self.height )
  6131. end
  6132.  
  6133. function IHasText:draw_text( surface, x, y )
  6134. local offset, lines = 0, self.text_lines
  6135.  
  6136. local horizontal_alignment = self.horizontal_alignment
  6137. local vertical_alignment = self.vertical_alignment
  6138.  
  6139. if not lines then
  6140. self:wrap_text()
  6141. lines = self.text_lines
  6142. end
  6143.  
  6144. if vertical_alignment == 1 then
  6145. offset = math.floor( self.height / 2 - #lines / 2 + .5 )
  6146. elseif vertical_alignment == 4 then
  6147. offset = self.height - #lines
  6148. end
  6149.  
  6150. for i = 1, #lines do
  6151.  
  6152. local x_offset = 0
  6153. if horizontal_alignment == 1 then
  6154. x_offset = math.floor( self.width / 2 - #lines[i] / 2 + .5 )
  6155. elseif horizontal_alignment == 2 then
  6156. x_offset = self.width - #lines[i]
  6157. end
  6158.  
  6159. surface:drawString( x + x_offset, y + offset + i - 1, lines[i], nil, self.text_colour )
  6160.  
  6161. end
  6162. end
  6163.  
  6164. function IHasText:on_pre_draw()
  6165. self:draw_text "default"
  6166. end
  6167.  
  6168. function wrapline( text, width )
  6169. if text:sub( 1, width ):find "\n" then
  6170. return text:match "^(.-)\n[^%S\n]*(.*)$"
  6171. end
  6172. if #text <= width then
  6173. return text
  6174. end
  6175. for i = width + 1, 1, -1 do
  6176. if text:sub( i, i ):find "%s" then
  6177. return text:sub( 1, i - 1 ):gsub( "[^%S\n]+$", "" ), text:sub( i + 1 ):gsub( "^[^%S\n]+", "" )
  6178. end
  6179. end
  6180. return text:sub( 1, width ), text:sub( width + 1 )
  6181. end
  6182.  
  6183. function wrap( text, width, height )
  6184. local lines, line = {}
  6185. while text and ( not height or #lines < height ) do
  6186. line, text = wrapline( text, width )
  6187. lines[#lines + 1] = line
  6188. end
  6189. return lines
  6190. end
  6191.  
  6192.  
  6193.  
  6194.  
  6195. Button = class.new( "Button", Sheet, IHasText, IColoured ) {
  6196. down = false;
  6197. colour = nil;
  6198. active_colour = nil;
  6199. horizontal_alignment = 1;
  6200. vertical_alignment = 1;
  6201. }
  6202.  
  6203. function Button:Button( x, y, width, height, text )
  6204. self:initialise()
  6205. self:IHasText()
  6206. self:IColoured()
  6207. self.values:add( "active_colour", 8 )
  6208. self:Sheet( x, y, width, height )
  6209.  
  6210. self:set_colour( 512 )
  6211. self:set_horizontal_alignment( 1 )
  6212. self:set_vertical_alignment( 1 )
  6213.  
  6214. if text then
  6215. self:set_text( text )
  6216. end
  6217. end
  6218.  
  6219. function Button:draw( surface, x, y )
  6220. surface:fillRect( x, y, self.width, self.height, self.down and self.active_colour or self.colour, 1, "" )
  6221. self:draw_text( surface, x, y )
  6222. self.changed = false
  6223. end
  6224.  
  6225. function Button:on_mouse_event( event )
  6226. if event:is( 1 ) and self.down then
  6227. self.down = false
  6228. self:set_changed()
  6229. end
  6230.  
  6231. if event.handled or not event:is_within_area( 0, 0, self.width, self.height ) or not event.within then
  6232. return
  6233. end
  6234.  
  6235. if event:is( 0 ) and not self.down then
  6236. self.down = true
  6237. self:set_changed()
  6238. event:handle()
  6239. elseif event:is( 2 ) then
  6240. if self.on_click then
  6241. self:on_click( event.button, event.x, event.y )
  6242. end
  6243. event:handle()
  6244. elseif event:is( 3 ) then
  6245. if self.on_hold then
  6246. self:on_hold( event.button, event.x, event.y )
  6247. end
  6248. event:handle()
  6249. end
  6250. end
  6251.  
  6252.  
  6253. -- @/require elements.Checkbox
  6254.  
  6255.  
  6256.  
  6257.  
  6258.  
  6259.  
  6260. ClippedContainer = class.new( "ClippedContainer", Container, nil ) {
  6261. surface = nil;
  6262. colour = nil;
  6263. }
  6264.  
  6265. function ClippedContainer:ClippedContainer( ... )
  6266. self.surface = surface.create( 0, 0 )
  6267.  
  6268. return self:Container( ... )
  6269. end
  6270.  
  6271. function ClippedContainer:draw( surface, x, y )
  6272. if self.changed then
  6273. local children = self.children
  6274. local cx, cy, cc
  6275. local x_offset, y_offset = self.x_offset, self.y_offset
  6276.  
  6277. self:reset_cursor_blink()
  6278. self.surface:clear( self.colour )
  6279.  
  6280. if self.on_pre_draw then
  6281. self:on_pre_draw()
  6282. end
  6283.  
  6284. for i = 1, #children do
  6285. local child = children[i]
  6286. if child:is_visible() then
  6287. child:draw( self.surface, child.x + x_offset, child.y + y_offset )
  6288.  
  6289. if child.cursor_active then
  6290. cx, cy, cc = child.x + child.cursor_x, child.y + child.cursor_y, child.cursor_colour
  6291. end
  6292. end
  6293. end
  6294.  
  6295. if cx then
  6296. self:set_cursor_blink( cx, cy, cc )
  6297. end
  6298.  
  6299. if self.on_post_draw then
  6300. self:on_post_draw()
  6301. end
  6302.  
  6303. self.changed = false
  6304. end
  6305.  
  6306. surface:drawSurface( self.surface, x, y )
  6307. end
  6308.  
  6309.  
  6310. -- @/require interfaces.IHasText
  6311. -- @/require elements.Draggable
  6312.  
  6313.  
  6314. -- @/require elements.Image
  6315.  
  6316.  
  6317.  
  6318.  
  6319.  
  6320.  
  6321. KeyHandler = class.new( "KeyHandler", Sheet, nil ) {
  6322. actions = {};
  6323. shortcuts = {};
  6324. handles_keyboard = true;
  6325. }
  6326.  
  6327. function KeyHandler:KeyHandler()
  6328. self.actions = {}
  6329. self.shortcuts = {}
  6330. self:initialise()
  6331. return self:Sheet( 0, 0, 0, 0 )
  6332. end
  6333.  
  6334. function KeyHandler:add_action( name, callback, ... )
  6335. for i = 1, #self.actions do
  6336. if self.actions[i].name == name then
  6337. Exception.throw( Exception( "KeyHandlerAction", "cannot create new action'" .. name .. "':action already exists" ) ) -- TODO: create custom exception for this
  6338. end
  6339. end
  6340.  
  6341. self.actions[#self.actions + 1] = {
  6342. name = name;
  6343. callback = callback;
  6344. parameters = { ... };
  6345. keybindings = {};
  6346. }
  6347. end
  6348.  
  6349. function KeyHandler:remove_action( name )
  6350. for i = 1, #self.actions do
  6351. if self.actions[i].name == name then
  6352. for j = 1, #self.actions[i].keybindings do
  6353. self:unbind_key( self.actions[i].keybindings[j] )
  6354. end
  6355.  
  6356. return table.remove( self.actions, i ).callback
  6357. end
  6358. end
  6359. end
  6360.  
  6361. function KeyHandler:set_callback( action, callback )
  6362. for i = 1, #self.actions do
  6363. if self.actions[i].name == action then
  6364. self.actions[i].callback = callback
  6365. return
  6366. end
  6367. end
  6368. end
  6369.  
  6370. function KeyHandler:set_parameters( action, parameters )
  6371. for i = 1, #self.actions do
  6372. if self.actions[i].name == action then
  6373. self.actions[i].parameters = parameters
  6374. return
  6375. end
  6376. end
  6377. end
  6378.  
  6379. function KeyHandler:bind_key( key, action )
  6380. if self.shortcuts[key] then
  6381. self:unbind_key( key )
  6382. end
  6383.  
  6384. for i = 1, #self.actions do
  6385. if self.actions[i].name == action then
  6386. self.actions[i].keybindings[#self.actions[i].keybindings + 1] = key
  6387. self.shortcuts[key] = action
  6388. return
  6389. end
  6390. end
  6391.  
  6392. Exception.throw( Exception( "KeyHandlerBindingException", "cannot bind key'" .. key .. "'to action'" .. action .. "':action doesn't exist" ) )
  6393. end
  6394.  
  6395. function KeyHandler:unbind_key( key )
  6396. local action = self.shortcuts[key]
  6397.  
  6398. if not action then
  6399. Exception.throw( Exception( "KeyHandlerBindingException", "cannot unbind key'" .. key .. "':key not bound" ) )
  6400. end
  6401.  
  6402. for i = 1, #self.actions do
  6403. if self.actions[i].name == action then
  6404. for j = 1, #self.actions[i].keybindings do
  6405. if self.actions[i].keybindings[j] == key then
  6406. table.remove( self.actions[i].keybindings, j )
  6407. break
  6408. end
  6409. end
  6410.  
  6411. self.shortcuts[key] = nil
  6412. return
  6413. end
  6414. end
  6415. end
  6416.  
  6417. function KeyHandler:on_keyboard_event( event )
  6418. if not event.handled and event:is( 7 ) then
  6419. local longest_match, longest_match_action
  6420. local actions = self.actions
  6421. local shortcuts = self.shortcuts
  6422. local k, v = next( shortcuts )
  6423.  
  6424. while k do
  6425. if event:matches( k ) then
  6426. if not longest_match or #k > #longest_match then
  6427. longest_match = k
  6428. longest_match_action = v
  6429. end
  6430. end
  6431.  
  6432. k, v = next( shortcuts, k )
  6433. end
  6434.  
  6435. if longest_match then
  6436. event:handle( self )
  6437.  
  6438. for i = 1, #actions do
  6439. if actions[i].name == longest_match_action then
  6440. return actions[i].callback( unpack( actions[i].parameters ) )
  6441. end
  6442. end
  6443. end
  6444. end
  6445. end
  6446.  
  6447. function KeyHandler:draw() end
  6448.  
  6449.  
  6450.  
  6451.  
  6452.  
  6453.  
  6454. Panel = class.new( "Panel", Sheet, IColoured ) {
  6455. colour = nil;
  6456. }
  6457.  
  6458. function Panel:Panel( x, y, w, h )
  6459. self:initialise()
  6460. self:IColoured()
  6461. return self:Sheet( x, y, w, h )
  6462. end
  6463.  
  6464. function Panel:draw( canvas, x, y )
  6465. canvas:fillRect( x, y, self.width, self.height, self.colour, 1, " " )
  6466. end
  6467.  
  6468.  
  6469. -- @/require elements.ScrollContainer
  6470.  
  6471.  
  6472. -- @/require interfaces.IHasText
  6473. -- @/require elements.Text
  6474.  
  6475.  
  6476. -- @/require elements.TextInput
  6477.  
  6478. sheets.KeyHandler = KeyHandler;sheets.ICollatedChildren = ICollatedChildren;sheets.KeyboardEvent = KeyboardEvent;sheets.Exception = Exception;sheets.Event = Event;sheets.ITimer = ITimer;sheets.class = class;sheets.QueryTracker = QueryTracker;sheets.Stream = Stream;sheets.Transition = Transition;sheets.Application = Application;sheets.IQueryable = IQueryable;sheets.ThreadRuntimeException = ThreadRuntimeException;sheets.Button = Button;sheets.MouseEvent = MouseEvent;sheets.ClippedContainer = ClippedContainer;sheets.ISize = ISize;sheets.TableType = TableType;sheets.Easing = Easing;sheets.MiscEvent = MiscEvent;sheets.IColoured = IColoured;sheets.Thread = Thread;sheets.Container = Container;sheets.TextEvent = TextEvent;sheets.parameters = parameters;sheets.Panel = Panel;sheets.ResourceLoadException = ResourceLoadException;sheets.Codegen = Codegen;sheets.Typechecking = Typechecking;sheets.UnionType = UnionType;sheets.ValueHandler = ValueHandler;sheets.IncorrectParameterException = IncorrectParameterException;sheets.DynamicValueParser = DynamicValueParser;sheets.Sheet = Sheet;sheets.IHasText = IHasText;sheets.Screen = Screen;sheets.Type = Type;sheets.IChildContainer = IChildContainer;sheets.IncorrectConstructorException = IncorrectConstructorException;sheets.ListType = ListType;sheets.clipboard = clipboard;sheets.ITagged = ITagged end
  6479.  
  6480. local app = sheets.Application()
  6481.  
  6482. app:run()
  6483. end )
  6484. if not ok then
  6485. local e = select( 2, pcall( error, "@", 2 ) )
  6486. local src = e:match "^(.*):%d+: @$"
  6487. local line, msg = err:match( src .. ":(%d+): (.*)" )
  6488.  
  6489. if line then
  6490. local src, line = __get_src_and_line( tonumber( line ) )
  6491. error( src .. "[" .. line .. "]: " .. __get_err_msg( src, line, msg ), 0 )
  6492. else
  6493. error( err, 0 )
  6494. end
  6495. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement