Advertisement
YangSapiens

Untitled

Jul 9th, 2024 (edited)
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.52 KB | None | 0 0
  1. local Os = {}
  2. Os.Work = true
  3. Os.Renderers = {}
  4.  
  5. local Vec2 = {} do
  6.     Vec2.__index = Vec2
  7.     function Vec2.New(x,y)
  8.         return setmetatable({X=x,Y=y},Vec2)
  9.     end
  10.     function Vec2:XY()
  11.         return self.X,self.Y        
  12.     end
  13.     function Vec2:__add(other)
  14.         return Vec2.New(self.X+other.X,self.Y+other.Y)
  15.     end
  16. end
  17. local BaseRenderer = {} do
  18.     BaseRenderer.__index = BaseRenderer
  19.     function BaseRenderer.New(pos,size,text,txtCol,bgCol,scroll)
  20.         return setmetatable({
  21.             Pos = pos,
  22.             Size = size,
  23.             Text = text,
  24.             TextColor = txtCol,
  25.             BackgroundColor = bgCol,
  26.             Scroll = scroll,
  27.             TextOffset = 0
  28.         }, BaseRenderer)
  29.     end
  30.     function BaseRenderer:ColorizeTerm()
  31.         local txtColor = self.TextColor or Screen.DefaultTextColor
  32.         term.setTextColor(txtColor)
  33.         local bgColor = self.BackgroundColor or Screen.DefaultBackgroundColor
  34.         term.setBackgroundColor(bgColor)
  35.     end
  36.     function BaseRenderer:RenderLine(line)
  37.         local text = self.Text
  38.         local width, height = self.Size:XY()
  39.         local yoff = line+(self.Scroll or 0)-1
  40.        
  41.         local start = math.min(#text+1,yoff*width+1)
  42.         local finish = math.min(#text+1,start+width-1)
  43.         local tx = start < 1 and "" or text:sub(start,finish)
  44.         return tx..(" "):rep(width-#tx)
  45.     end
  46.     function BaseRenderer:Render()
  47.         self:ColorizeTerm()
  48.         local pX, pY = self.Pos:XY()
  49.         for y=1, self.Size.Y do
  50.             term.setCursorPos(pX,pY+y-1)
  51.             term.write(self:RenderLine(y))
  52.         end
  53.         self.TextOffset = 0
  54.     end
  55. end
  56.  
  57. local InputService = {} do
  58.     local Connected = {}
  59.     function InputService.Connect(obj,name)
  60.         Connected[obj] = function(e,k)
  61.             obj[name](obj,e,k)
  62.         end    
  63.     end
  64.     function InputService.Disconnect(obj)
  65.         Connected[obj] = nil        
  66.     end    
  67.     function InputService.Run()
  68.         while Os.Work do
  69.             local event, key = os.pullEvent( "key" )
  70.             for _,v in pairs(Connected) do
  71.                 v(event, key)                
  72.             end
  73.         end
  74.     end        
  75. end
  76.  
  77. local RendererMaker = {} do
  78.     local Addons = {} do
  79.         function Addons.Frame(renderer)
  80.             local renderFn = renderer.RenderLine
  81.             function renderer.RenderLine (self,line)
  82.                 local px,py = self.Pos:XY()
  83.                 local width,height = self.Size:XY()
  84.                 if line == 1 or line == height then
  85.                     local text = line == 1 and "press Q to close" or ""
  86.                     return '+'..text..("-"):rep(width-#text)..'+'
  87.                 end
  88.                 local actualLine = line-1
  89.                 local rightch = (self.Scroll == actualLine-1 and '<') or '|'
  90.                 return '|'..renderFn(self,actualLine)..rightch
  91.             end
  92.         end
  93.         function Addons.AdvancedText(renderer)
  94.             function renderer.RenderLine(self,line)
  95.                 local width, height = self.Size:XY()
  96.                 local text = self.Text
  97.                 local textoffset = self.TextOffset
  98.                 local yoff = line+(self.Scroll or 0)-1
  99.                 local soffset = yoff*width
  100.                
  101.                 local start, ends = 1+soffset+textoffset,width+soffset+textoffset
  102.                 if start<1 then
  103.                     return (" "):rep(width)
  104.                 end
  105.                 local s = text:sub(start, ends)
  106.                 local nline = s:find('\n')
  107.                 local cnext = text:sub(ends+1,ends+1)
  108.                 if nline then
  109.                     s = s:sub(1,nline-1)..(' '):rep(width-nline+1)
  110.                     self.TextOffset = textoffset - width + nline
  111.                 elseif cnext == '\n' then
  112.                     self.TextOffset = textoffset + 1
  113.                 else
  114.                     local i = s:reverse():find(' ')
  115.                     if i and (cnext~='' and cnext~=' ' and cnext~='\n') then
  116.                         self.TextOffset = textoffset - i + 1
  117.                         s = s:sub(1,-i)
  118.                     end
  119.                     if #s<width then s = s..(' '):rep(width-#s) end
  120.                 end
  121.                 return s
  122.            end
  123.         end            
  124.         function Addons.InputEvent(renderer, handler)
  125.             renderer.InputHandle = handler
  126.         end
  127.     end
  128.     local Creator = {} do
  129.         Creator.__index = Creator
  130.         function Creator.New()
  131.             return setmetatable({Addons = {}, Methods = {}},Creator)
  132.         end
  133.         function Creator:DEVAdd(name)
  134.             self.Addons[name] = true
  135.             return self
  136.         end
  137.         function Creator:AddMethod(name,method)
  138.             self.Methods[name] = method
  139.             return self
  140.         end
  141.         function Creator:AddAdvancedText()
  142.             self.Addons.AdvancedText = {}
  143.             return self
  144.         end            
  145.         function Creator:AddInputEvent(handler)
  146.             self.Addons.InputEvent = {handler}
  147.             return self
  148.         end            
  149.         function Creator:AddFrame()
  150.             self.Addons.Frame = {}
  151.             return self
  152.         end
  153.         function Creator:Remove(name)
  154.             self.Addons[name] = nil
  155.             return self
  156.         end            
  157.         function Creator:End(newMaker,Base)
  158.             Base = Base or BaseRenderer
  159.             local Renderer = setmetatable({},Base)
  160.             Renderer.__index = Renderer
  161.             Renderer.Creator = self
  162.             self.NewMaker = newMaker or function(self)
  163.                 return function(...)
  164.                     local base = Base.New(...)
  165.                     return setmetatable(base,Renderer)
  166.                 end
  167.             end
  168.             Renderer.New = self.NewMaker(Renderer)
  169.             for i,v in pairs(self.Methods) do
  170.                 Renderer[i] = v
  171.             end
  172.             for i,v in pairs(self.Addons) do
  173.                 print(Addons[i],i)
  174.                 Addons[i](Renderer,table.unpack(v))
  175.             end
  176.             return Renderer
  177.         end
  178.     end            
  179.     function RendererMaker.Begin()
  180.         return Creator.New()
  181.     end
  182. end
  183.  
  184. local MyRenderer = RendererMaker.Begin()
  185.     :AddAdvancedText()
  186.     :AddFrame()
  187.     :AddFrame()
  188.     :AddInputEvent(function(self,event,key)
  189.         if key == keys.down then
  190.             self.Scroll = self.Scroll + 1
  191.         elseif key == keys.up then
  192.             self.Scroll = self.Scroll - 1
  193.         elseif key == keys.q then
  194.             self:Close()
  195.         elseif key == keys.right then
  196.             self.Size.X = self.Size.X+1
  197.         elseif key == keys.left then
  198.             self.Size.X = self.Size.X-1
  199.         end
  200.     end)
  201.     :AddMethod("Close",function(self)
  202.         Os.Renderers[self] = nil
  203.         InputService.Disconnect(self)
  204.     end)
  205. :End(function(self)
  206.     return function(...)
  207.         local Base = BaseRenderer
  208.         local base = Base.New(...)
  209.         local obj = setmetatable(base,self)
  210.         InputService.Connect(obj,"InputHandle")
  211.         Os.Renderers[obj] = obj
  212.         return obj
  213.     end
  214. end)
  215.  
  216. local Screen = {} do
  217.     Screen.DefaultBackgroundColor = colors.black
  218.     Screen.DefaultTextColor = colors.white
  219.     function Screen.Clear()
  220.         term.setBackgroundColor(Screen.DefaultBackgroundColor)
  221.         term.setTextColor(Screen.DefaultTextColor)
  222.         local sX,sY = term.getSize()
  223.          for y=1, sY do
  224.             term.setCursorPos(1,y)
  225.             term.write((" "):rep(sX))
  226.         end
  227.     end
  228. end
  229. Screen.BaseRenderer = BaseRenderer
  230.  
  231. Os.Screen = Screen
  232.  
  233. function Main()
  234.     local rect1 = MyRenderer.New(
  235.         Vec2.New(1,1),
  236.         Vec2.New(30,10),
  237.         [[Hello, World!]],
  238.         colors.red,
  239.         colors.yellow,
  240.         0
  241.     )
  242.     while Os.Work do
  243.         Screen.Clear()
  244.         for _,v in pairs(Os.Renderers) do
  245.             v:Render()
  246.         end
  247.         sleep(1/24)
  248.     end
  249. end
  250. parallel.waitForAll(Main,InputService.Run)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement