tArgs = {...} if OneOS then --running under OneOS OneOS.ToolBarColour = colours.grey OneOS.ToolBarTextColour = colours.white end local _w, _h = term.getSize() local round = function(num, idp) local mult = 10^(idp or 0) return math.floor(num * mult + 0.5) / mult end UIColours = { Toolbar = colours.grey, ToolbarText = colours.lightGrey, ToolbarSelected = colours.lightBlue, ControlText = colours.white, ToolbarItemTitle = colours.black, Background = colours.lightGrey, MenuBackground = colours.white, MenuText = colours.black, MenuSeparatorText = colours.grey, MenuDisabledText = colours.lightGrey, Shadow = colours.grey, TransparentBackgroundOne = colours.white, TransparentBackgroundTwo = colours.lightGrey, MenuBarActive = colours.white } local getNames = peripheral.getNames or function() local tResults = {} for n,sSide in ipairs( rs.getSides() ) do if peripheral.isPresent( sSide ) then table.insert( tResults, sSide ) local isWireless = false if not pcall(function()isWireless = peripheral.call(sSide, 'isWireless') end) then isWireless = true end if peripheral.getType( sSide ) == "modem" and not isWireless then local tRemote = peripheral.call( sSide, "getNamesRemote" ) for n,sName in ipairs( tRemote ) do table.insert( tResults, sName ) end end end end return tResults end Peripheral = { GetPeripheral = function(_type) for i, p in ipairs(Peripheral.GetPeripherals()) do if p.Type == _type then return p end end end, Call = function(type, ...) local tArgs = {...} local p = Peripheral.GetPeripheral(type) peripheral.call(p.Side, unpack(tArgs)) end, GetPeripherals = function(filterType) local peripherals = {} for i, side in ipairs(getNames()) do local name = peripheral.getType(side):gsub("^%l", string.upper) local code = string.upper(side:sub(1,1)) if side:find('_') then code = side:sub(side:find('_')+1) end local dupe = false for i, v in ipairs(peripherals) do if v[1] == name .. ' ' .. code then dupe = true end end if not dupe then local _type = peripheral.getType(side) local isWireless = false if _type == 'modem' then if not pcall(function()isWireless = peripheral.call(sSide, 'isWireless') end) then isWireless = true end if isWireless then _type = 'wireless_modem' name = 'W '..name end end if not filterType or _type == filterType then table.insert(peripherals, {Name = name:sub(1,8) .. ' '..code, Fullname = name .. ' ('..side:sub(1, 1):upper() .. side:sub(2, -1)..')', Side = side, Type = _type, Wireless = isWireless}) end end end return peripherals end, PresentNamed = function(name) return peripheral.isPresent(name) end, CallType = function(type, ...) local tArgs = {...} local p = GetPeripheral(type) return peripheral.call(p.Side, unpack(tArgs)) end, CallNamed = function(name, ...) local tArgs = {...} return peripheral.call(name, unpack(tArgs)) end } TextLine = { Text = "", Alignment = AlignmentLeft, Initialise = function(self, text, alignment) local new = {} -- the new instance setmetatable( new, {__index = self} ) new.Text = text new.Alignment = alignment or AlignmentLeft return new end } local StripColours = function(str) return str:gsub('['..string.char(14)..'-'..string.char(29)..']','') end Printer = { Name = nil, PeripheralType = 'printer', paperLevel = function(self) return Peripheral.CallNamed(self.Name, 'getPaperLevel') end, newPage = function(self) return Peripheral.CallNamed(self.Name, 'newPage') end, endPage = function(self) return Peripheral.CallNamed(self.Name, 'endPage') end, pageWrite = function(self, text) return Peripheral.CallNamed(self.Name, 'write', text) end, setPageTitle = function(self, title) return Peripheral.CallNamed(self.Name, 'setPageTitle', title) end, inkLevel = function(self) return Peripheral.CallNamed(self.Name, 'getInkLevel') end, getCursorPos = function(self) return Peripheral.CallNamed(self.Name, 'getCursorPos') end, setCursorPos = function(self, x, y) return Peripheral.CallNamed(self.Name, 'setCursorPos', x, y) end, pageSize = function(self) return Peripheral.CallNamed(self.Name, 'getPageSize') end, Present = function() if Peripheral.GetPeripheral(Printer.PeripheralType) == nil then return false else return true end end, PrintLines = function(self, lines, title, copies) local pages = {} local pageLines = {} for i, line in ipairs(lines) do table.insert(pageLines, TextLine:Initialise(StripColours(line))) if i % 25 == 0 then table.insert(pages, pageLines) pageLines = {} end end if #pageLines ~= 0 then table.insert(pages, pageLines) end return self:PrintPages(pages, title, copies) end, PrintPages = function(self, pages, title, copies) copies = copies or 1 for c = 1, copies do for p, page in ipairs(pages) do if self:paperLevel() < #pages * copies then return 'Add more paper to the printer' end if self:inkLevel() < #pages * copies then return 'Add more ink to the printer' end self:newPage() for i, line in ipairs(page) do self:setCursorPos(1, i) self:pageWrite(StripColours(line.Text)) end if title then self:setPageTitle(title) end self:endPage() end end end, Initialise = function(self, name) if Printer.Present() then --fix local new = {} -- the new instance setmetatable( new, {__index = self} ) if name and Peripheral.PresentNamed(name) then new.Name = name else new.Name = Peripheral.GetPeripheral(Printer.PeripheralType).Side end return new end end } Clipboard = { Content = nil, Type = nil, IsCut = false, Empty = function() Clipboard.Content = nil Clipboard.Type = nil Clipboard.IsCut = false end, isEmpty = function() return Clipboard.Content == nil end, Copy = function(content, _type) Clipboard.Content = content Clipboard.Type = _type or 'generic' Clipboard.IsCut = false end, Cut = function(content, _type) Clipboard.Content = content Clipboard.Type = _type or 'generic' Clipboard.IsCut = true end, Paste = function() local c, t = Clipboard.Content, Clipboard.Type if Clipboard.IsCut then Clipboard.Empty() end return c, t end } if OneOS and OneOS.Clipboard then Clipboard = OneOS.Clipboard end Drawing = { Screen = { Width = _w, Height = _h }, DrawCharacters = function (x, y, characters, textColour,bgColour) Drawing.WriteStringToBuffer(x, y, characters, textColour, bgColour) end, DrawBlankArea = function (x, y, w, h, colour) Drawing.DrawArea (x, y, w, h, " ", 1, colour) end, DrawArea = function (x, y, w, h, character, textColour, bgColour) --width must be greater than 1, other wise we get a stack overflow if w < 0 then w = w * -1 elseif w == 0 then w = 1 end for ix = 1, w do local currX = x + ix - 1 for iy = 1, h do local currY = y + iy - 1 Drawing.WriteToBuffer(currX, currY, character, textColour, bgColour) end end end, DrawImage = function(_x,_y,tImage, w, h) if tImage then for y = 1, h do if not tImage[y] then break end for x = 1, w do if not tImage[y][x] then break end local bgColour = tImage[y][x] local textColour = tImage.textcol[y][x] or colours.white local char = tImage.text[y][x] Drawing.WriteToBuffer(x+_x-1, y+_y-1, char, textColour, bgColour) end end elseif w and h then Drawing.DrawBlankArea(x, y, w, h, colours.green) end end, --using .nft LoadImage = function(path) local image = { text = {}, textcol = {} } local fs = fs if OneOS then fs = OneOS.FS end if fs.exists(path) then local _open = io.open if OneOS then _open = OneOS.IO.open end local file = _open(path, "r") local sLine = file:read() local num = 1 while sLine do table.insert(image, num, {}) table.insert(image.text, num, {}) table.insert(image.textcol, num, {}) --As we're no longer 1-1, we keep track of what index to write to local writeIndex = 1 --Tells us if we've hit a 30 or 31 (BG and FG respectively)- next char specifies the curr colour local bgNext, fgNext = false, false --The current background and foreground colours local currBG, currFG = nil,nil for i=1,#sLine do local nextChar = string.sub(sLine, i, i) if nextChar:byte() == 30 then bgNext = true elseif nextChar:byte() == 31 then fgNext = true elseif bgNext then currBG = Drawing.GetColour(nextChar) bgNext = false elseif fgNext then currFG = Drawing.GetColour(nextChar) fgNext = false else if nextChar ~= " " and currFG == nil then currFG = colours.white end image[num][writeIndex] = currBG image.textcol[num][writeIndex] = currFG image.text[num][writeIndex] = nextChar writeIndex = writeIndex + 1 end end num = num+1 sLine = file:read() end file:close() end return image end, DrawCharactersCenter = function(x, y, w, h, characters, textColour,bgColour) w = w or Drawing.Screen.Width h = h or Drawing.Screen.Height x = x or 0 y = y or 0 x = math.ceil((w - #characters) / 2) + x y = math.floor(h / 2) + y Drawing.DrawCharacters(x, y, characters, textColour, bgColour) end, GetColour = function(hex) if hex == ' ' then return colours.transparent end local value = tonumber(hex, 16) if not value then return nil end value = math.pow(2,value) return value end, Clear = function (_colour) _colour = _colour or colours.black Drawing.ClearBuffer() Drawing.DrawBlankArea(1, 1, Drawing.Screen.Width, Drawing.Screen.Height, _colour) end, Buffer = {}, BackBuffer = {}, DrawBuffer = function() for y,row in pairs(Drawing.Buffer) do for x,pixel in pairs(row) do local shouldDraw = true local hasBackBuffer = true if Drawing.BackBuffer[y] == nil or Drawing.BackBuffer[y][x] == nil or #Drawing.BackBuffer[y][x] ~= 3 then hasBackBuffer = false end if hasBackBuffer and Drawing.BackBuffer[y][x][1] == Drawing.Buffer[y][x][1] and Drawing.BackBuffer[y][x][2] == Drawing.Buffer[y][x][2] and Drawing.BackBuffer[y][x][3] == Drawing.Buffer[y][x][3] then shouldDraw = false end if shouldDraw then term.setBackgroundColour(pixel[3]) term.setTextColour(pixel[2]) term.setCursorPos(x, y) term.write(pixel[1]) end end end Drawing.BackBuffer = Drawing.Buffer Drawing.Buffer = {} term.setCursorPos(1,1) end, ClearBuffer = function() Drawing.Buffer = {} end, WriteStringToBuffer = function (x, y, characters, textColour,bgColour) for i = 1, #characters do local character = characters:sub(i,i) Drawing.WriteToBuffer(x + i - 1, y, character, textColour, bgColour) end end, WriteToBuffer = function(x, y, character, textColour,bgColour) x = round(x) y = round(y) if bgColour == colours.transparent then Drawing.Buffer[y] = Drawing.Buffer[y] or {} Drawing.Buffer[y][x] = Drawing.Buffer[y][x] or {"", colours.white, colours.black} Drawing.Buffer[y][x][1] = character Drawing.Buffer[y][x][2] = textColour else Drawing.Buffer[y] = Drawing.Buffer[y] or {} Drawing.Buffer[y][x] = {character, textColour, bgColour} end end, } Current = { Document = nil, TextInput = nil, CursorPos = {1,1}, CursorColour = colours.black, Selection = {8, 36}, Window = nil, Modified = false, } local isQuitting = false function OrderSelection() if Current.Selection then if Current.Selection[1] <= Current.Selection[2] then return Current.Selection else return {Current.Selection[2], Current.Selection[1]} end end end function StripColours(str) return str:gsub('['..string.char(14)..'-'..string.char(29)..']','') end function FindColours(str) local _, count = str:gsub('['..string.char(14)..'-'..string.char(29)..']','') return count end ColourFromCharacter = function(character) local n = character:byte() - 14 if n > 16 then return nil else return 2^n end end CharacterFromColour = function(colour) return string.char(math.floor(math.log(colour)/math.log(2))+14) end Events = {} Button = { X = 1, Y = 1, Width = 0, Height = 0, BackgroundColour = colours.lightGrey, TextColour = colours.white, ActiveBackgroundColour = colours.lightGrey, Text = "", Parent = nil, _Click = nil, Toggle = nil, AbsolutePosition = function(self) return self.Parent:AbsolutePosition() end, Draw = function(self) local bg = self.BackgroundColour local tc = self.TextColour if type(bg) == 'function' then bg = bg() end if self.Toggle then tc = UIColours.MenuBarActive bg = self.ActiveBackgroundColour end local pos = GetAbsolutePosition(self) Drawing.DrawBlankArea(pos.X, pos.Y, self.Width, self.Height, bg) Drawing.DrawCharactersCenter(pos.X, pos.Y, self.Width, self.Height, self.Text, tc, bg) end, Initialise = function(self, x, y, width, height, backgroundColour, parent, click, text, textColour, toggle, activeBackgroundColour) local new = {} -- the new instance setmetatable( new, {__index = self} ) height = height or 1 new.Width = width or #text + 2 new.Height = height new.Y = y new.X = x new.Text = text or "" new.BackgroundColour = backgroundColour or colours.lightGrey new.TextColour = textColour or colours.white new.ActiveBackgroundColour = activeBackgroundColour or colours.lightGrey new.Parent = parent new._Click = click new.Toggle = toggle return new end, Click = function(self, side, x, y) if self._Click then if self:_Click(side, x, y, not self.Toggle) ~= false and self.Toggle ~= nil then self.Toggle = not self.Toggle Draw() end return true else return false end end } TextBox = { X = 1, Y = 1, Width = 0, Height = 0, BackgroundColour = colours.lightGrey, TextColour = colours.black, Parent = nil, TextInput = nil, Placeholder = '', AbsolutePosition = function(self) return self.Parent:AbsolutePosition() end, Draw = function(self) local pos = GetAbsolutePosition(self) Drawing.DrawBlankArea(pos.X, pos.Y, self.Width, self.Height, self.BackgroundColour) local text = self.TextInput.Value if #tostring(text) > (self.Width - 2) then text = text:sub(#text-(self.Width - 3)) if Current.TextInput == self.TextInput then Current.CursorPos = {pos.X + 1 + self.Width-2, pos.Y} end else if Current.TextInput == self.TextInput then Current.CursorPos = {pos.X + 1 + self.TextInput.CursorPos, pos.Y} end end if #tostring(text) == 0 then Drawing.DrawCharacters(pos.X + 1, pos.Y, self.Placeholder, colours.lightGrey, self.BackgroundColour) else Drawing.DrawCharacters(pos.X + 1, pos.Y, text, self.TextColour, self.BackgroundColour) end term.setCursorBlink(true) Current.CursorColour = self.TextColour end, Initialise = function(self, x, y, width, height, parent, text, backgroundColour, textColour, done, numerical) local new = {} -- the new instance setmetatable( new, {__index = self} ) height = height or 1 new.Width = width or #text + 2 new.Height = height new.Y = y new.X = x new.TextInput = TextInput:Initialise(text or '', function(key) if done then done(key) end Draw() end, numerical) new.BackgroundColour = backgroundColour or colours.lightGrey new.TextColour = textColour or colours.black new.Parent = parent return new end, Click = function(self, side, x, y) Current.Input = self.TextInput self:Draw() end } TextInput = { Value = "", Change = nil, CursorPos = nil, Numerical = false, IsDocument = nil, Initialise = function(self, value, change, numerical, isDocument) local new = {} -- the new instance setmetatable( new, {__index = self} ) new.Value = tostring(value) new.Change = change new.CursorPos = #tostring(value) new.Numerical = numerical new.IsDocument = isDocument or false return new end, Insert = function(self, str) if self.Numerical then str = tostring(tonumber(str)) end local selection = OrderSelection() if self.IsDocument and selection then self.Value = string.sub(self.Value, 1, selection[1]-1) .. str .. string.sub( self.Value, selection[2]+2) self.CursorPos = selection[1] Current.Selection = nil else local _, newLineAdjust = string.gsub(self.Value:sub(1, self.CursorPos), '\n','') self.Value = string.sub(self.Value, 1, self.CursorPos + newLineAdjust) .. str .. string.sub( self.Value, self.CursorPos + 1 + newLineAdjust) self.CursorPos = self.CursorPos + 1 end self.Change(key) end, Extract = function(self, remove) local selection = OrderSelection() if self.IsDocument and selection then local _, newLineAdjust = string.gsub(self.Value:sub(selection[1], selection[2]), '\n','') local str = string.sub(self.Value, selection[1], selection[2]+1+newLineAdjust) if remove then self.Value = string.sub(self.Value, 1, selection[1]-1) .. string.sub( self.Value, selection[2]+2+newLineAdjust) self.CursorPos = selection[1] - 1 Current.Selection = nil end return str end end, Char = function(self, char) if char == 'nil' then return end self:Insert(char) end, Key = function(self, key) if key == keys.enter then if self.IsDocument then self.Value = string.sub(self.Value, 1, self.CursorPos ) .. '\n' .. string.sub( self.Value, self.CursorPos + 1 ) self.CursorPos = self.CursorPos + 1 end self.Change(key) elseif key == keys.left then -- Left if self.CursorPos > 0 then local colShift = FindColours(string.sub( self.Value, self.CursorPos, self.CursorPos)) self.CursorPos = self.CursorPos - 1 - colShift self.Change(key) end elseif key == keys.right then -- Right if self.CursorPos < string.len(self.Value) then local colShift = FindColours(string.sub( self.Value, self.CursorPos+1, self.CursorPos+1)) self.CursorPos = self.CursorPos + 1 + colShift self.Change(key) end elseif key == keys.backspace then -- Backspace if self.IsDocument and Current.Selection then self:Extract(true) self.Change(key) elseif self.CursorPos > 0 then local colShift = FindColours(string.sub( self.Value, self.CursorPos, self.CursorPos)) local _, newLineAdjust = string.gsub(self.Value:sub(1, self.CursorPos), '\n','') self.Value = string.sub( self.Value, 1, self.CursorPos - 1 - colShift + newLineAdjust) .. string.sub( self.Value, self.CursorPos + 1 - colShift + newLineAdjust) self.CursorPos = self.CursorPos - 1 - colShift self.Change(key) end elseif key == keys.home then -- Home self.CursorPos = 0 self.Change(key) elseif key == keys.delete then if self.IsDocument and Current.Selection then self:Extract(true) self.Change(key) elseif self.CursorPos < string.len(self.Value) then self.Value = string.sub( self.Value, 1, self.CursorPos ) .. string.sub( self.Value, self.CursorPos + 2 ) self.Change(key) end elseif key == keys["end"] then -- End self.CursorPos = string.len(self.Value) self.Change(key) elseif key == keys.up and self.IsDocument then -- Up if Current.Document.CursorPos then local page = Current.Document.Pages[Current.Document.CursorPos.Page] self.CursorPos = page:GetCursorPosFromPoint(Current.Document.CursorPos.Collum + page.MarginX, Current.Document.CursorPos.Line - page.MarginY - 1 + Current.Document.ScrollBar.Scroll, true) self.Change(key) end elseif key == keys.down and self.IsDocument then -- Down if Current.Document.CursorPos then local page = Current.Document.Pages[Current.Document.CursorPos.Page] self.CursorPos = page:GetCursorPosFromPoint(Current.Document.CursorPos.Collum + page.MarginX, Current.Document.CursorPos.Line - page.MarginY + 1 + Current.Document.ScrollBar.Scroll, true) self.Change(key) end end end } Menu = { X = 0, Y = 0, Width = 0, Height = 0, Owner = nil, Items = {}, RemoveTop = false, Draw = function(self) Drawing.DrawBlankArea(self.X + 1, self.Y + 1, self.Width, self.Height, UIColours.Shadow) if not self.RemoveTop then Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, UIColours.MenuBackground) for i, item in ipairs(self.Items) do if item.Separator then Drawing.DrawArea(self.X, self.Y + i, self.Width, 1, '-', colours.grey, UIColours.MenuBackground) else local textColour = item.Colour or UIColours.MenuText if (item.Enabled and type(item.Enabled) == 'function' and item.Enabled() == false) or item.Enabled == false then textColour = UIColours.MenuDisabledText end Drawing.DrawCharacters(self.X + 1, self.Y + i, item.Title, textColour, UIColours.MenuBackground) end end else Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, UIColours.MenuBackground) for i, item in ipairs(self.Items) do if item.Separator then Drawing.DrawArea(self.X, self.Y + i - 1, self.Width, 1, '-', colours.grey, UIColours.MenuBackground) else local textColour = item.Colour or UIColours.MenuText if (item.Enabled and type(item.Enabled) == 'function' and item.Enabled() == false) or item.Enabled == false then textColour = UIColours.MenuDisabledText end Drawing.DrawCharacters(self.X + 1, self.Y + i - 1, item.Title, textColour, UIColours.MenuBackground) Drawing.DrawCharacters(self.X - 1 + self.Width-#item.KeyName, self.Y + i - 1, item.KeyName, textColour, UIColours.MenuBackground) end end end end, NameForKey = function(self, key) if key == keys.leftCtrl then return '^' elseif key == keys.tab then return 'Tab' elseif key == keys.delete then return 'Delete' elseif key == keys.n then return 'N' elseif key == keys.a then return 'A' elseif key == keys.s then return 'S' elseif key == keys.o then return 'O' elseif key == keys.z then return 'Z' elseif key == keys.y then return 'Y' elseif key == keys.c then return 'C' elseif key == keys.x then return 'X' elseif key == keys.v then return 'V' elseif key == keys.r then return 'R' elseif key == keys.l then return 'L' elseif key == keys.t then return 'T' elseif key == keys.h then return 'H' elseif key == keys.e then return 'E' elseif key == keys.p then return 'P' elseif key == keys.f then return 'F' elseif key == keys.m then return 'M' elseif key == keys.q then return 'Q' else return '?' end end, Initialise = function(self, x, y, items, owner, removeTop) local new = {} -- the new instance setmetatable( new, {__index = self} ) if not owner then return end local keyNames = {} for i, v in ipairs(items) do items[i].KeyName = '' if v.Keys then for _i, key in ipairs(v.Keys) do items[i].KeyName = items[i].KeyName .. self:NameForKey(key) end end if items[i].KeyName ~= '' then table.insert(keyNames, items[i].KeyName) end end local keysLength = LongestString(keyNames) if keysLength > 0 then keysLength = keysLength + 2 end new.Width = LongestString(items, 'Title') + 2 + keysLength if new.Width < 10 then new.Width = 10 end new.Height = #items + 2 new.RemoveTop = removeTop or false if removeTop then new.Height = new.Height - 1 end if y < 1 then y = 1 end if x < 1 then x = 1 end if y + new.Height > Drawing.Screen.Height + 1 then y = Drawing.Screen.Height - new.Height end if x + new.Width > Drawing.Screen.Width + 1 then x = Drawing.Screen.Width - new.Width end new.Y = y new.X = x new.Items = items new.Owner = owner return new end, New = function(self, x, y, items, owner, removeTop) if Current.Menu and Current.Menu.Owner == owner then Current.Menu = nil return end local new = self:Initialise(x, y, items, owner, removeTop) Current.Menu = new return new end, Click = function(self, side, x, y) local i = y-1 if self.RemoveTop then i = y end if i >= 1 and y < self.Height then if not ((self.Items[i].Enabled and type(self.Items[i].Enabled) == 'function' and self.Items[i].Enabled() == false) or self.Items[i].Enabled == false) and self.Items[i].Click then self.Items[i]:Click() if Current.Menu.Owner and Current.Menu.Owner.Toggle then Current.Menu.Owner.Toggle = false end Current.Menu = nil self = nil end return true end end } MenuBar = { X = 1, Y = 1, Width = Drawing.Screen.Width, Height = 1, MenuBarItems = {}, AbsolutePosition = function(self) return {X = self.X, Y = self.Y} end, Draw = function(self) --Drawing.DrawArea(self.X - 1, self.Y, 1, self.Height, "|", UIColours.ToolbarText, UIColours.Background) Drawing.DrawBlankArea(self.X, self.Y, self.Width, self.Height, colours.grey) for i, button in ipairs(self.MenuBarItems) do button:Draw() end end, Initialise = function(self, items) local new = {} -- the new instance setmetatable( new, {__index = self} ) new.X = 1 new.Y = 1 new.MenuBarItems = items return new end, AddToolbarItem = function(self, item) table.insert(self.ToolbarItems, item) self:CalculateToolbarItemPositions() end, CalculateToolbarItemPositions = function(self) local currY = 1 for i, toolbarItem in ipairs(self.ToolbarItems) do toolbarItem.Y = currY currY = currY + toolbarItem.Height end end, Click = function(self, side, x, y) for i, item in ipairs(self.MenuBarItems) do if item.X <= x and item.X + item.Width > x then if item:Click(item, side, x - item.X + 1, 1) then return true end end end return false end } TextFormatPlainText = 1 TextFormatInkText = 2 Document = { X = 1, Y = 1, PageSize = {Width = 25, Height = 21}, TextInput = nil, Pages = {}, Format = TextFormatPlainText, Title = '', Path = nil, ScrollBar = nil, Lines = {}, CursorPos = nil, CalculateLineWrapping = function(self) local limit = self.PageSize.Width local text = self.TextInput.Value local lines = {''} local words = {} for word, space in text:gmatch('(%S+)(%s*)') do for i = 1, math.ceil(#word/limit) do local _space = '' if i == math.ceil(#word/limit) then _space = space end table.insert(words, {word:sub(1+limit*(i-1), limit*i), _space}) end end for i, ws in ipairs(words) do local word = ws[1] local space = ws[2] local temp = lines[#lines] .. word .. space:gsub('\n','') if #temp > limit then table.insert(lines, '') end if space:find('\n') then lines[#lines] = lines[#lines] .. word space = space:gsub('\n', function() table.insert(lines, '') return '' end) else lines[#lines] = lines[#lines] .. word .. space end end return lines end, CalculateCursorPos = function(self) local passedCharacters = 0 Current.CursorPos = nil for p, page in ipairs(self.Pages) do page:Draw() if not Current.CursorPos then for i, line in ipairs(page.Lines) do local relCursor = self.TextInput.CursorPos - FindColours(self.TextInput.Value:sub(1,self.TextInput.CursorPos)) if passedCharacters + #StripColours(line.Text:gsub('\n','')) >= relCursor then Current.CursorPos = {self.X + page.MarginX + (relCursor - passedCharacters), page.Y + 1 + i} self.CursorPos = {Page = p, Line = i, Collum = relCursor - passedCharacters - FindColours(self.TextInput.Value:sub(1,self.TextInput.CursorPos-1))} break end passedCharacters = passedCharacters + #StripColours(line.Text:gsub('\n','')) end end end end, Draw = function(self) self:CalculatePages() self:CalculateCursorPos() self.ScrollBar:Draw() end, CalculatePages = function(self) self.Pages = {} local lines = self:CalculateLineWrapping() self.Lines = lines local pageLines = {} local totalPageHeight = (3 + self.PageSize.Height + 2 * Page.MarginY) for i, line in ipairs(lines) do table.insert(pageLines, TextLine:Initialise(line)) if i % self.PageSize.Height == 0 then table.insert(self.Pages, Page:Initialise(self, pageLines, 3 - self.ScrollBar.Scroll + totalPageHeight*(#self.Pages))) pageLines = {} end end if #pageLines ~= 0 then table.insert(self.Pages, Page:Initialise(self, pageLines, 3 - self.ScrollBar.Scroll + totalPageHeight*(#self.Pages))) end self.ScrollBar.MaxScroll = totalPageHeight*(#self.Pages) - Drawing.Screen.Height + 1 end, ScrollToCursor = function(self) self:CalculateCursorPos() if Current.CursorPos and (Current.CursorPos[2] > Drawing.Screen.Height or Current.CursorPos[2] < 2) then self.ScrollBar:DoScroll(Current.CursorPos[2] - Drawing.Screen.Height) end end, SetSelectionColour = function(self, colour) local selection = OrderSelection() local text = self.TextInput:Extract(true) local colChar = CharacterFromColour(colour) local precedingColour = '' if FindColours(self.TextInput.Value:sub(self.TextInput.CursorPos+1, self.TextInput.CursorPos+1)) == 0 then for i = 1, self.TextInput.CursorPos do local c = self.TextInput.Value:sub(self.TextInput.CursorPos - i,self.TextInput.CursorPos - i) if FindColours(c) == 1 then precedingColour = c break end end if precedingColour == '' then precedingColour = CharacterFromColour(colours.black) end end self.TextInput:Insert(colChar..StripColours(text)..precedingColour) --text = text:gsub('['..string.char(14)..'-'..string.char(29)..']','') end, Initialise = function(self, text, title, path) local new = {} -- the new instance setmetatable( new, {__index = self} ) new.Title = title or 'New Document' new.Path = path new.X = (Drawing.Screen.Width - (new.PageSize.Width + 2*(Page.MarginX)))/2 new.Y = 2 new.TextInput = TextInput:Initialise(text, function() new:ScrollToCursor() Current.Modified = true Draw() end, false, true) new.ScrollBar = ScrollBar:Initialise(Drawing.Screen.Width, new.Y, Drawing.Screen.Height-1, 0, nil, nil, nil, function()end) Current.TextInput = new.TextInput Current.ScrollBar = new.ScrollBar return new end } ScrollBar = { X = 1, Y = 1, Width = 1, Height = 1, BackgroundColour = colours.grey, BarColour = colours.lightBlue, Parent = nil, Change = nil, Scroll = 0, MaxScroll = 0, ClickPoint = nil, AbsolutePosition = function(self) return self.Parent:AbsolutePosition() end, Draw = function(self) local pos = GetAbsolutePosition(self) local barHeight = self.Height - self.MaxScroll if barHeight < 3 then barHeight = 3 end local percentage = (self.Scroll/self.MaxScroll) Drawing.DrawBlankArea(pos.X, pos.Y, self.Width, self.Height, self.BackgroundColour) Drawing.DrawBlankArea(pos.X, pos.Y + round(self.Height*percentage - barHeight*percentage), self.Width, barHeight, self.BarColour) end, Initialise = function(self, x, y, height, maxScroll, backgroundColour, barColour, parent, change) local new = {} -- the new instance setmetatable( new, {__index = self} ) new.Width = 1 new.Height = height new.Y = y new.X = x new.BackgroundColour = backgroundColour or colours.grey new.BarColour = barColour or colours.lightBlue new.Parent = parent new.Change = change or function()end new.MaxScroll = maxScroll new.Scroll = 0 return new end, DoScroll = function(self, amount) amount = round(amount) if self.Scroll < 0 or self.Scroll > self.MaxScroll then return false end self.Scroll = self.Scroll + amount if self.Scroll < 0 then self.Scroll = 0 elseif self.Scroll > self.MaxScroll then self.Scroll = self.MaxScroll end self.Change() return true end, Click = function(self, side, x, y, drag) local percentage = (self.Scroll/self.MaxScroll) local barHeight = (self.Height - self.MaxScroll) if barHeight < 3 then barHeight = 3 end local relScroll = (self.MaxScroll*(y + barHeight*percentage)/self.Height) if not drag then self.ClickPoint = self.Scroll - relScroll + 1 end if self.Scroll-1 ~= relScroll then self:DoScroll(relScroll-self.Scroll-1 + self.ClickPoint) end return true end } AlignmentLeft = 1 AlignmentCentre = 2 AlignmentRight = 3 TextLine = { Text = "", Alignment = AlignmentLeft, Initialise = function(self, text, alignment) local new = {} -- the new instance setmetatable( new, {__index = self} ) new.Text = text new.Alignment = alignment or AlignmentLeft return new end } local clickPos = 1 Page = { X = 1, Y = 1, Width = 1, Height = 1, MarginX = 3, MarginY = 2, BackgroundColour = colours.white, TextColour = colours.white, ActiveBackgroundColour = colours.lightGrey, Lines = {}, Parent = nil, AbsolutePosition = function(self) return self.Parent:AbsolutePosition() end, Draw = function(self) local pos = GetAbsolutePosition(self) if pos.Y > Drawing.Screen.Height or pos.Y + self.Height < 1 then return end Drawing.DrawBlankArea(pos.X+self.Width,pos.Y -1 + 1, 1, self.Height, UIColours.Shadow) Drawing.DrawBlankArea(pos.X+1, pos.Y -1 + self.Height, self.Width, 1, UIColours.Shadow) Drawing.DrawBlankArea(pos.X, pos.Y -1, self.Width, self.Height, self.BackgroundColour) local textColour = self.TextColour if not Current.Selection then for i, line in ipairs(self.Lines) do local _c = 1 for c = 1, #line.Text do local col = ColourFromCharacter(line.Text:sub(c,c)) if col then textColour = col else Drawing.WriteToBuffer(pos.X + self.MarginX - 1 + _c, pos.Y -2 + i + self.MarginY, line.Text:sub(c,c), textColour, self.BackgroundColour) _c = _c + 1 end end end else local selection = OrderSelection() local char = 1 local textColour = self.TextColour for i, line in ipairs(self.Lines) do local _c = 1 for c = 1, #line.Text do local col = ColourFromCharacter(line.Text:sub(c,c)) if col then textColour = col else local tc = textColour local colour = colours.white if char >= selection[1] and char <= selection[2] then colour = colours.lightBlue tc = colours.white end Drawing.WriteToBuffer(pos.X + self.MarginX - 1 + _c, pos.Y -2 + i + self.MarginY, line.Text:sub(c,c), tc, colour) _c = _c + 1 end char = char + 1 end end end end, Initialise = function(self, parent, lines, y) local new = {} -- the new instanc setmetatable( new, {__index = self} ) new.Height = parent.PageSize.Height + 2 * self.MarginY new.Width = parent.PageSize.Width + 2 * self.MarginX new.X = 1 new.Y = y or 1 new.Lines = lines or {} new.BackgroundColour = colours.white new.TextColour = colours.black new.Parent = parent new.ClickPos = 1 return new end, GetCursorPosFromPoint = function(self, x, y, rel) local pos = GetAbsolutePosition(self) if rel then pos = {Y = 0, X = 0} end local row = y - pos.Y + self.MarginY - self.Parent.ScrollBar.Scroll local col = x - self.MarginX - pos.X + 1 local cursorPos = 0 if row <= 0 or col <= 0 then return 0 end if row > #self.Lines then for i, v in ipairs(self.Lines) do cursorPos = cursorPos + #v.Text-- - FindColours(v.Text) end return cursorPos end --term.setCursorPos(1,3) local prevLineCount = 0 for i, v in ipairs(self.Lines) do if i == row then if col > #v.Text then col = #v.Text-- + FindColours(v.Text) else col = col + FindColours(v.Text:sub(1, col)) end --term.setCursorPos(1,2) --print(prevLineCount) cursorPos = cursorPos + col + 2 - i - prevLineCount break else prevLineCount = FindColours(v.Text) if prevLineCount ~= 0 then prevLineCount = prevLineCount end cursorPos = cursorPos + #v.Text + 2 - i + FindColours(v.Text) end end return cursorPos - 2 end, Click = function(self, side, x, y, drag) local cursorPos = self:GetCursorPosFromPoint(x, y) self.Parent.TextInput.CursorPos = cursorPos if drag == nil then Current.Selection = nil clickPos = x else local relCursor = cursorPos-- - FindColours(self.Parent.TextInput.Value:sub(1,cursorPos)) + 1 if not Current.Selection then local adder = 1 if clickPos and clickPos < x then adder = 0 end Current.Selection = {relCursor + adder, relCursor + 1 + adder} else Current.Selection[2] = relCursor + 1 end end Draw() return true end } function GetAbsolutePosition(object) local obj = object local i = 0 local x = 1 local y = 1 while true do x = x + obj.X - 1 y = y + obj.Y - 1 if not obj.Parent then return {X = x, Y = y} end obj = obj.Parent if i > 32 then return {X = 1, Y = 1} end i = i + 1 end end function Draw() if not Current.Window then Drawing.Clear(colours.lightGrey) else Drawing.DrawArea(1, 2, Drawing.Screen.Width, Drawing.Screen.Height, '|', colours.black, colours.lightGrey) end if Current.Document then Current.Document:Draw() end Current.MenuBar:Draw() if Current.Window then Current.Window:Draw() end if Current.Menu then Current.Menu:Draw() end Drawing.DrawBuffer() if Current.TextInput and Current.CursorPos and not Current.Menu and not(Current.Window and Current.Document and Current.TextInput == Current.Document.TextInput) and Current.CursorPos[2] > 1 then term.setCursorPos(Current.CursorPos[1], Current.CursorPos[2]) term.setCursorBlink(true) term.setTextColour(Current.CursorColour) else term.setCursorBlink(false) end end MainDraw = Draw LongestString = function(input, key) local length = 0 for i = 1, #input do local value = input[i] if key then if value[key] then value = value[key] else value = '' end end local titleLength = string.len(value) if titleLength > length then length = titleLength end end return length end function LoadMenuBar() Current.MenuBar = MenuBar:Initialise({ Button:Initialise(1, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle) if toggle then Menu:New(1, 2, { { Title = "New...", Click = function() Current.Document = Document:Initialise('') end, Keys = { keys.leftCtrl, keys.n } }, { Title = 'Open...', Click = function() DisplayOpenDocumentWindow() end, Keys = { keys.leftCtrl, keys.o } }, { Separator = true }, { Title = 'Save...', Click = function() SaveDocument() end, Keys = { keys.leftCtrl, keys.s }, Enabled = function() return true end }, { Separator = true }, { Title = 'Print...', Click = function() PrintDocument() end, Keys = { keys.leftCtrl, keys.p }, Enabled = function() return true end }, { Separator = true }, { Title = 'Quit', Click = function() Close() end }, --[[ { Title = 'Save As...', Click = function() end } ]]-- }, self, true) else Current.Menu = nil end return true end, 'File', colours.lightGrey, false), Button:Initialise(7, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle) if not self.Toggle then Menu:New(7, 2, { --[[ { Title = "Undo", Click = function() end, Keys = { keys.leftCtrl, keys.z }, Enabled = function() return false end }, { Title = 'Redo', Click = function() end, Keys = { keys.leftCtrl, keys.y }, Enabled = function() return false end }, { Separator = true }, ]]-- { Title = 'Cut', Click = function() Clipboard.Cut(Current.Document.TextInput:Extract(true), 'text') end, Keys = { keys.leftCtrl, keys.x }, Enabled = function() return Current.Document ~= nil and Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil end }, { Title = 'Copy', Click = function() Clipboard.Copy(Current.Document.TextInput:Extract(), 'text') end, Keys = { keys.leftCtrl, keys.c }, Enabled = function() return Current.Document ~= nil and Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil end }, { Title = 'Paste', Click = function() local paste = Clipboard.Paste() Current.Document.TextInput:Insert(paste) Current.Document.TextInput.CursorPos = Current.Document.TextInput.CursorPos + #paste - 1 end, Keys = { keys.leftCtrl, keys.v }, Enabled = function() return Current.Document ~= nil and (not Clipboard.isEmpty()) and Clipboard.Type == 'text' end }, { Separator = true, }, { Title = 'Select All', Click = function() Current.Selection = {1, #Current.Document.TextInput.Value:gsub('\n','')} end, Keys = { keys.leftCtrl, keys.a }, Enabled = function() return Current.Document ~= nil end } }, self, true) else Current.Menu = nil end return true end, 'Edit', colours.lightGrey, false) }) end function LoadMenuBar() Current.MenuBar = MenuBar:Initialise({ Button:Initialise(1, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle) if toggle then Menu:New(1, 2, { { Title = "New...", Click = function() Current.Document = Document:Initialise('') end, Keys = { keys.leftCtrl, keys.n } }, { Title = 'Open...', Click = function() DisplayOpenDocumentWindow() end, Keys = { keys.leftCtrl, keys.o } }, { Separator = true }, { Title = 'Save...', Click = function() SaveDocument() end, Keys = { keys.leftCtrl, keys.s }, Enabled = function() return Current.Document ~= nil end }, { Separator = true }, { Title = 'Print...', Click = function() PrintDocument() end, Keys = { keys.leftCtrl, keys.p }, Enabled = function() return true end }, { Separator = true }, { Title = 'Quit', Click = function() if Close() and OneOS then OneOS.Close() end end, Keys = { keys.leftCtrl, keys.q } }, --[[ { Title = 'Save As...', Click = function() end } ]]-- }, self, true) else Current.Menu = nil end return true end, 'File', colours.lightGrey, false), Button:Initialise(7, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle) if not self.Toggle then Menu:New(7, 2, { --[[ { Title = "Undo", Click = function() end, Keys = { keys.leftCtrl, keys.z }, Enabled = function() return false end }, { Title = 'Redo', Click = function() end, Keys = { keys.leftCtrl, keys.y }, Enabled = function() return false end }, { Separator = true }, ]]-- { Title = 'Cut', Click = function() Clipboard.Cut(Current.Document.TextInput:Extract(true), 'text') end, Keys = { keys.leftCtrl, keys.x }, Enabled = function() return Current.Document ~= nil and Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil end }, { Title = 'Copy', Click = function() Clipboard.Copy(Current.Document.TextInput:Extract(), 'text') end, Keys = { keys.leftCtrl, keys.c }, Enabled = function() return Current.Document ~= nil and Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil end }, { Title = 'Paste', Click = function() local paste = Clipboard.Paste() Current.Document.TextInput:Insert(paste) Current.Document.TextInput.CursorPos = Current.Document.TextInput.CursorPos + #paste - 1 end, Keys = { keys.leftCtrl, keys.v }, Enabled = function() return Current.Document ~= nil and (not Clipboard.isEmpty()) and Clipboard.Type == 'text' end }, { Separator = true, }, { Title = 'Select All', Click = function() Current.Selection = {1, #Current.Document.TextInput.Value:gsub('\n','')} end, Keys = { keys.leftCtrl, keys.a }, Enabled = function() return Current.Document ~= nil end } }, self, true) else Current.Menu = nil end return true end, 'Edit', colours.lightGrey, false), Button:Initialise(13, 1, nil, nil, colours.grey, Current.MenuBar, function(self, side, x, y, toggle) if not self.Toggle then Menu:New(13, 2, { { Title = 'Red', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.red, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end }, { Title = 'Orange', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.orange, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end }, { Title = 'Yellow', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.yellow, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end }, { Title = 'Pink', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.pink, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end }, { Title = 'Magenta', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.magenta, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end }, { Title = 'Purple', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.purple, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end }, { Title = 'Light Blue', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.lightBlue, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end }, { Title = 'Cyan', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.cyan, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end }, { Title = 'Blue', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.blue, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end }, { Title = 'Green', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.green, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end }, { Title = 'Light Grey', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.lightGrey, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end }, { Title = 'Grey', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.grey, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end }, { Title = 'Black', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.black, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end }, { Title = 'Brown', Click = function(item) Current.Document:SetSelectionColour(item.Colour) end, Colour = colours.brown, Enabled = function() return (Current.Document ~= nil and Current.Selection ~= nil and Current.Selection[1] ~= nil and Current.Selection[2] ~= nil) end } }, self, true) else Current.Menu = nil end return true end, 'Colour', colours.lightGrey, false) }) end function SplashScreen() local w = colours.white local b = colours.black local u = colours.blue local lb = colours.lightBlue local splashIcon = {{w,w,w,b,w,w,w,b,w,w,w,},{w,w,w,b,w,w,w,b,w,w,w,},{w,w,w,b,u,u,u,b,w,w,w,},{w,b,b,u,u,u,u,u,b,b,w,},{b,u,u,lb,lb,u,u,u,u,u,b,},{b,u,lb,lb,u,u,u,u,u,u,b,},{b,u,lb,lb,u,u,u,u,u,u,b,},{b,u,u,u,u,u,u,u,u,u,b,},{w,b,b,b,b,b,b,b,b,b,w,}, ["text"]={{" "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," ",},{" "," "," "," ","I","n","k"," "," "," "," ",},{" "," "," "," "," "," "," "," "," "," "," ",},{" "," ","b","y"," ","o","e","e","d"," "," "},{" "," "," "," "," "," "," "," "," "," "," ",},}, ["textcol"]={{w,w,w,w,w,w,w,w,w,w,w,},{w,w,w,w,w,w,w,w,w,w,w,},{w,w,w,w,w,w,w,w,w,w,w,},{w,w,w,w,w,w,w,w,w,w,w,},{w,w,w,w,w,w,w,w,w,w,w,},{w,w,w,w,w,w,w,w,w,w,w,},{w,w,w,w,w,w,w,w,w,w,w,},{lb,lb,lb,lb,lb,lb,lb,lb,lb,lb,lb,},{w,w,w,w,w,w,w,w,w,w,w,},},} Drawing.Clear(colours.white) Drawing.DrawImage((Drawing.Screen.Width - 11)/2, (Drawing.Screen.Height - 9)/2, splashIcon, 11, 9) Drawing.DrawBuffer() Drawing.Clear(colours.black) parallel.waitForAny(function()sleep(1)end, function()os.pullEvent('mouse_click')end) end function Initialise(arg) if OneOS then fs = OneOS.FS end if not OneOS then SplashScreen() end EventRegister('mouse_click', TryClick) EventRegister('mouse_drag', function(event, side, x, y)TryClick(event, side, x, y, true)end) EventRegister('mouse_scroll', Scroll) EventRegister('key', HandleKey) EventRegister('char', HandleKey) EventRegister('timer', Timer) EventRegister('terminate', function(event) if Close() then error( "Terminated", 0 ) end end) LoadMenuBar() --Current.Document = Document:Initialise('abcdefghijklmnopqrtuvwxy')--'Hello everybody!') if tArgs[1] then if fs.exists(tArgs[1]) then OpenDocument(tArgs[1]) else --new end else Current.Document = Document:Initialise('')--'Hello everybody!') end --[[ if arg and fs.exists(arg) then OpenDocument(arg) else DisplayNewDocumentWindow() end ]]-- Draw() EventHandler() end local isControlPushed = false controlPushedTimer = nil closeWindowTimer = nil function Timer(event, timer) if timer == closeWindowTimer then if Current.Window then Current.Window:Close() end Draw() elseif timer == controlPushedTimer then isControlPushed = false end end local ignoreNextChar = false function HandleKey(...) local args = {...} local event = args[1] local keychar = args[2] --Mac left command character if event == 'key' and keychar == keys.leftCtrl or keychar == keys.rightCtrl or keychar == 219 then isControlPushed = true controlPushedTimer = os.startTimer(0.5) elseif isControlPushed then if event == 'key' then if CheckKeyboardShortcut(keychar) then isControlPushed = false ignoreNextChar = true end end elseif ignoreNextChar then ignoreNextChar = false elseif Current.TextInput then if event == 'char' then Current.TextInput:Char(keychar) elseif event == 'key' then Current.TextInput:Key(keychar) end end end function CheckKeyboardShortcut(key) local shortcuts = {} shortcuts[keys.n] = function() Current.Document = Document:Initialise('') end shortcuts[keys.o] = function() DisplayOpenDocumentWindow() end shortcuts[keys.s] = function() if Current.Document ~= nil then SaveDocument() end end shortcuts[keys.left] = function() if Current.TextInput then Current.TextInput:Key(keys.home) end end shortcuts[keys.right] = function() if Current.TextInput then Current.TextInput:Key(keys["end"]) end end -- shortcuts[keys.q] = function() DisplayOpenDocumentWindow() end if Current.Document ~= nil then shortcuts[keys.s] = function() SaveDocument() end shortcuts[keys.p] = function() PrintDocument() end if Current.Selection and Current.Selection[1] and Current.Selection[2] ~= nil then shortcuts[keys.x] = function() Clipboard.Cut(Current.Document.TextInput:Extract(true), 'text') end shortcuts[keys.c] = function() Clipboard.Copy(Current.Document.TextInput:Extract(), 'text') end end if (not Clipboard.isEmpty()) and Clipboard.Type == 'text' then shortcuts[keys.v] = function() local paste = Clipboard.Paste() Current.Document.TextInput:Insert(paste) Current.Document.TextInput.CursorPos = Current.Document.TextInput.CursorPos + #paste - 1 end end shortcuts[keys.a] = function() Current.Selection = {1, #Current.Document.TextInput.Value:gsub('\n','')} end end if shortcuts[key] then shortcuts[key]() Draw() return true else return false end end --[[ Check if the given object falls under the click coordinates ]]-- function CheckClick(object, x, y) if object.X <= x and object.Y <= y and object.X + object.Width > x and object.Y + object.Height > y then return true end end --[[ Attempt to clicka given object ]]-- function DoClick(object, side, x, y, drag) local obj = GetAbsolutePosition(object) obj.Width = object.Width obj.Height = object.Height if object and CheckClick(obj, x, y) then return object:Click(side, x - object.X + 1, y - object.Y + 1, drag) end end --[[ Try to click at the given coordinates ]]-- function TryClick(event, side, x, y, drag) if Current.Menu then if DoClick(Current.Menu, side, x, y, drag) then Draw() return else if Current.Menu.Owner and Current.Menu.Owner.Toggle then Current.Menu.Owner.Toggle = false end Current.Menu = nil Draw() return end elseif Current.Window then if DoClick(Current.Window, side, x, y, drag) then Draw() return else Current.Window:Flash() return end end local interfaceElements = {} table.insert(interfaceElements, Current.MenuBar) table.insert(interfaceElements, Current.ScrollBar) for i, page in ipairs(Current.Document.Pages) do table.insert(interfaceElements, page) end for i, object in ipairs(interfaceElements) do if DoClick(object, side, x, y, drag) then Draw() return end end Draw() end function Scroll(event, direction, x, y) if Current.Window and Current.Window.OpenButton then Current.Document.Scroll = Current.Document.Scroll + direction if Current.Window.Scroll < 0 then Current.Window.Scroll = 0 elseif Current.Window.Scroll > Current.Window.MaxScroll then Current.Window.Scroll = Current.Window.MaxScroll end Draw() elseif Current.ScrollBar then if Current.ScrollBar:DoScroll(direction*2) then Draw() end end end --[[ Registers functions to run on certain events ]]-- function EventRegister(event, func) if not Events[event] then Events[event] = {} end table.insert(Events[event], func) end --[[ The main loop event handler, runs registered event functinos ]]-- function EventHandler() while true do local event, arg1, arg2, arg3, arg4 = os.pullEventRaw() if Events[event] then for i, e in ipairs(Events[event]) do e(event, arg1, arg2, arg3, arg4) end end end end local function Extension(path, addDot) if not path then return nil elseif not string.find(fs.getName(path), '%.') then if not addDot then return fs.getName(path) else return '' end else local _path = path if path:sub(#path) == '/' then _path = path:sub(1,#path-1) end local extension = _path:gmatch('%.[0-9a-z]+$')() if extension then extension = extension:sub(2) else --extension = nil return '' end if addDot then extension = '.'..extension end return extension:lower() end end local RemoveExtension = function(path) if path:sub(1,1) == '.' then return path end local extension = Extension(path) if extension == path then return fs.getName(path) end return string.gsub(path, extension, ''):sub(1, -2) end local acknowledgedColour = false function PrintDocument() if OneOS then OneOS.LoadAPI('/System/API/Helpers.lua') OneOS.LoadAPI('/System/API/Peripheral.lua') OneOS.LoadAPI('/System/API/Printer.lua') end local doPrint = function() local window = PrintDocumentWindow:Initialise():Show() end if Peripheral.GetPeripheral('printer') == nil then ButtonDialougeWindow:Initialise('No Printer Found', 'Please place a printer next to your computer. Ensure you also insert dye (left slot) and paper (top slots)', 'Ok', nil, function(window, ok) window:Close() end):Show() elseif not acknowledgedColour and FindColours(Current.Document.TextInput.Value) ~= 0 then ButtonDialougeWindow:Initialise('Important', 'Due to the way printers work, you can\'t print in more than one colour. The dye you use will be the colour of the text.', 'Ok', nil, function(window, ok) acknowledgedColour = true window:Close() doPrint() end):Show() else doPrint() end end function SaveDocument() local function save() local h = fs.open(Current.Document.Path, 'w') if h then if Current.Document.Format == TextFormatPlainText then h.write(Current.Document.TextInput.Value) else local lines = {} for p, page in ipairs(Current.Document.Pages) do for i, line in ipairs(page.Lines) do table.insert(lines, line) end end h.write(textutils.serialize(lines)) end Current.Modified = false else ButtonDialougeWindow:Initialise('Error', 'An error occured while saving the file, try again.', 'Ok', nil, function(window, ok) window:Close() end):Show() end h.close() end if not Current.Document.Path then SaveDocumentWindow:Initialise(function(self, success, path) self:Close() if success then local extension = '' if Current.Document.Format == TextFormatPlainText then extension = '.txt' elseif Current.Document.Format == TextFormatInkText then extension = '.ink' end if path:sub(-4) ~= extension then path = path .. extension end Current.Document.Path = path Current.Document.Title = fs.getName(path) save() end if Current.Document then Current.TextInput = Current.Document.TextInput end end):Show() else save() end end function DisplayOpenDocumentWindow() OpenDocumentWindow:Initialise(function(self, success, path) self:Close() if success then OpenDocument(path) end end):Show() end function OpenDocument(path) Current.Selection = nil local h = fs.open(path, 'r') if h then Current.Document = Document:Initialise(h.readAll(), RemoveExtension(fs.getName(path)), path) else ButtonDialougeWindow:Initialise('Error', 'An error occured while opening the file, try again.', 'Ok', nil, function(window, ok) window:Close() if Current.Document then Current.TextInput = Current.Document.TextInput end end):Show() end h.close() end local TidyPath = function(path) path = '/'..path local fs = fs if OneOS then fs = OneOS.FS end if fs.isDir(path) then path = path .. '/' end path, n = path:gsub("//", "/") while n > 0 do path, n = path:gsub("//", "/") end return path end OpenDocumentWindow = { X = 1, Y = 1, Width = 0, Height = 0, CursorPos = 1, Visible = true, Return = nil, OpenButton = nil, PathTextBox = nil, CurrentDirectory = '/', Scroll = 0, MaxScroll = 0, GoUpButton = nil, SelectedFile = '', Files = {}, Typed = false, AbsolutePosition = function(self) return {X = self.X, Y = self.Y} end, Draw = function(self) if not self.Visible then return end Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey) Drawing.DrawBlankArea(self.X, self.Y, self.Width, 3, colours.lightGrey) Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-6, colours.white) Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey) Drawing.DrawBlankArea(self.X, self.Y + self.Height - 5, self.Width, 5, colours.lightGrey) self:DrawFiles() if (fs.exists(self.PathTextBox.TextInput.Value)) or (self.SelectedFile and #self.SelectedFile > 0 and fs.exists(self.CurrentDirectory .. self.SelectedFile)) then self.OpenButton.TextColour = colours.black else self.OpenButton.TextColour = colours.lightGrey end self.PathTextBox:Draw() self.OpenButton:Draw() self.CancelButton:Draw() self.GoUpButton:Draw() end, DrawFiles = function(self) for i, file in ipairs(self.Files) do if i > self.Scroll and i - self.Scroll <= 11 then if file == self.SelectedFile then Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.white, colours.lightBlue) elseif string.find(file, '%.txt') or string.find(file, '%.text') or string.find(file, '%.ink') or fs.isDir(self.CurrentDirectory .. file) then Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.black, colours.white) else Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.grey, colours.white) end end end self.MaxScroll = #self.Files - 11 if self.MaxScroll < 0 then self.MaxScroll = 0 end end, Initialise = function(self, returnFunc) local new = {} -- the new instance setmetatable( new, {__index = self} ) new.Width = 32 new.Height = 17 new.Return = returnFunc new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2) new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2) new.Title = 'Open Document' new.Visible = true new.CurrentDirectory = '/' new.SelectedFile = nil if OneOS and fs.exists('/Desktop/Documents/') then new.CurrentDirectory = '/Desktop/Documents/' end new.OpenButton = Button:Initialise(new.Width - 6, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle) if fs.exists(new.PathTextBox.TextInput.Value) and self.TextColour == colours.black and not fs.isDir(new.PathTextBox.TextInput.Value) then returnFunc(new, true, TidyPath(new.PathTextBox.TextInput.Value)) elseif new.SelectedFile and self.TextColour == colours.black and fs.isDir(new.CurrentDirectory .. new.SelectedFile) then new:GoToDirectory(new.CurrentDirectory .. new.SelectedFile) elseif new.SelectedFile and self.TextColour == colours.black then returnFunc(new, true, TidyPath(new.CurrentDirectory .. '/' .. new.SelectedFile)) end end, 'Open', colours.black) new.CancelButton = Button:Initialise(new.Width - 15, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle) returnFunc(new, false) end, 'Cancel', colours.black) new.GoUpButton = Button:Initialise(2, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle) local folderName = fs.getName(new.CurrentDirectory) local parentDirectory = new.CurrentDirectory:sub(1, #new.CurrentDirectory-#folderName-1) new:GoToDirectory(parentDirectory) end, 'Go Up', colours.black) new.PathTextBox = TextBox:Initialise(2, new.Height - 3, new.Width - 2, 1, new, new.CurrentDirectory, colours.white, colours.black) new:GoToDirectory(new.CurrentDirectory) return new end, Show = function(self) Current.Window = self return self end, Close = function(self) Current.Input = nil Current.Window = nil self = nil end, GoToDirectory = function(self, path) path = TidyPath(path) self.CurrentDirectory = path self.Scroll = 0 self.SelectedFile = nil self.Typed = false self.PathTextBox.TextInput.Value = path local fs = fs if OneOS then fs = OneOS.FS end self.Files = fs.list(self.CurrentDirectory) Draw() end, Flash = function(self) self.Visible = false Draw() sleep(0.15) self.Visible = true Draw() sleep(0.15) self.Visible = false Draw() sleep(0.15) self.Visible = true Draw() end, Click = function(self, side, x, y) local items = {self.OpenButton, self.CancelButton, self.PathTextBox, self.GoUpButton} local found = false for i, v in ipairs(items) do if CheckClick(v, x, y) then v:Click(side, x, y) found = true end end if not found then if y <= 12 then local fs = fs if OneOS then fs = OneOS.FS end self.SelectedFile = fs.list(self.CurrentDirectory)[y-1] self.PathTextBox.TextInput.Value = TidyPath(self.CurrentDirectory .. '/' .. self.SelectedFile) Draw() end end return true end } PrintDocumentWindow = { X = 1, Y = 1, Width = 0, Height = 0, CursorPos = 1, Visible = true, Return = nil, PrintButton = nil, CopiesTextBox = nil, Scroll = 0, MaxScroll = 0, PrinterSelectButton = nil, Title = '', Status = 0, --0 = neutral, 1 = good, -1 = error StatusText = '', SelectedPrinter = nil, AbsolutePosition = function(self) return {X = self.X, Y = self.Y} end, Draw = function(self) if not self.Visible then return end Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey) Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey) Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white) Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey) self.PrinterSelectButton:Draw() Drawing.DrawCharactersCenter(self.X, self.Y + self.PrinterSelectButton.Y - 2, self.Width, 1, 'Printer', colours.black, colours.white) Drawing.DrawCharacters(self.X + self.Width - 3, self.Y + self.PrinterSelectButton.Y - 1, '\\/', colours.black, colours.lightGrey) Drawing.DrawCharacters(self.X + 1, self.Y + self.CopiesTextBox.Y - 1, 'Copies', colours.black, colours.white) local statusColour = colours.grey if self.Status == -1 then statusColour = colours.red elseif self.Status == 1 then statusColour = colours.green end Drawing.DrawCharacters(self.X + 1, self.Y + self.CopiesTextBox.Y + 1, self.StatusText, statusColour, colours.white) self.CopiesTextBox:Draw() self.PrintButton:Draw() self.CancelButton:Draw() end, Initialise = function(self) local new = {} -- the new instance setmetatable( new, {__index = self} ) new.Width = 32 new.Height = 11 new.Return = returnFunc new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2) new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2) new.Title = 'Print Document' new.Visible = true new.PrintButton = Button:Initialise(new.Width - 7, new.Height - 1, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle) local doPrint = true if new.SelectedPrinter == nil then local p = Peripheral.GetPeripheral('printer') if p then new.SelectedPrinter = p.Side new.PrinterSelectButton.Text = p.Fullname else new.StatusText = 'No Connected Printer' new.Status = -1 doPrint = false end end if doPrint then local printer = Printer:Initialise(new.SelectedPrinter) local err = printer:PrintLines(Current.Document.Lines, Current.Document.Title, tonumber(new.CopiesTextBox.TextInput.Value)) if not err then new.StatusText = 'Document Printed!' new.Status = 1 closeWindowTimer = os.startTimer(1) else new.StatusText = err new.Status = -1 end end end, 'Print', colours.black) new.CancelButton = Button:Initialise(new.Width - 15, new.Height - 1, nil, nil, colours.lightGrey, new, function(self, side, x, y, toggle) new:Close() Draw() end, 'Close', colours.black) new.PrinterSelectButton = Button:Initialise(2, 4, new.Width - 2, nil, colours.lightGrey, new, function(self, side, x, y, toggle) local printers = { { Title = "Automatic", Click = function() new.SelectedPrinter = nil new.PrinterSelectButton.Text = 'Automatic' end }, { Separator = true } } for i, p in ipairs(Peripheral.GetPeripherals('printer')) do table.insert(printers, { Title = p.Fullname, Click = function(self) new.SelectedPrinter = p.Side new.PrinterSelectButton.Text = p.Fullname end }) end Current.Menu = Menu:New(x, y+4, printers, self, true) end, 'Automatic', colours.black) new.CopiesTextBox = TextBox:Initialise(9, 6, 4, 1, new, 1, colours.lightGrey, colours.black, nil, true) Current.TextInput = new.CopiesTextBox.TextInput new.StatusText = 'Waiting...' new.Status = 0 return new end, Show = function(self) Current.Window = self return self end, Close = function(self) Current.Input = nil Current.Window = nil self = nil end, Flash = function(self) self.Visible = false Draw() sleep(0.15) self.Visible = true Draw() sleep(0.15) self.Visible = false Draw() sleep(0.15) self.Visible = true Draw() end, Click = function(self, side, x, y) local items = {self.PrintButton, self.CancelButton, self.CopiesTextBox, self.PrinterSelectButton} for i, v in ipairs(items) do if CheckClick(v, x, y) then v:Click(side, x, y) end end return true end } SaveDocumentWindow = { X = 1, Y = 1, Width = 0, Height = 0, CursorPos = 1, Visible = true, Return = nil, SaveButton = nil, PathTextBox = nil, CurrentDirectory = '/', Scroll = 0, MaxScroll = 0, ScrollBar = nil, GoUpButton = nil, Files = {}, Typed = false, AbsolutePosition = function(self) return {X = self.X, Y = self.Y} end, Draw = function(self) if not self.Visible then return end Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey) Drawing.DrawBlankArea(self.X, self.Y, self.Width, 3, colours.lightGrey) Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-6, colours.white) Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey) Drawing.DrawBlankArea(self.X, self.Y + self.Height - 5, self.Width, 5, colours.lightGrey) Drawing.DrawCharacters(self.X + 1, self.Y + self.Height - 5, self.CurrentDirectory, colours.grey, colours.lightGrey) self:DrawFiles() if (self.PathTextBox.TextInput.Value) then self.SaveButton.TextColour = colours.black else self.SaveButton.TextColour = colours.lightGrey end self.PathTextBox:Draw() self.SaveButton:Draw() self.CancelButton:Draw() self.GoUpButton:Draw() end, DrawFiles = function(self) for i, file in ipairs(self.Files) do if i > self.Scroll and i - self.Scroll <= 10 then if file == self.SelectedFile then Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.white, colours.lightBlue) elseif fs.isDir(self.CurrentDirectory .. file) then Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.black, colours.white) else Drawing.DrawCharacters(self.X + 1, self.Y + i - self.Scroll, file, colours.lightGrey, colours.white) end end end self.MaxScroll = #self.Files - 11 if self.MaxScroll < 0 then self.MaxScroll = 0 end end, Initialise = function(self, returnFunc) local new = {} -- the new instance setmetatable( new, {__index = self} ) new.Width = 32 new.Height = 16 new.Return = returnFunc new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2) new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2) new.Title = 'Save Document' new.Visible = true new.CurrentDirectory = '/' if OneOS and fs.exists('/Desktop/Documents/') then new.CurrentDirectory = '/Desktop/Documents/' end new.SaveButton = Button:Initialise(new.Width - 6, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle) if self.TextColour == colours.black and not fs.isDir(new.CurrentDirectory ..'/' .. new.PathTextBox.TextInput.Value) then returnFunc(new, true, TidyPath(new.CurrentDirectory ..'/' .. new.PathTextBox.TextInput.Value)) elseif new.SelectedFile and self.TextColour == colours.black and fs.isDir(new.CurrentDirectory .. new.SelectedFile) then new:GoToDirectory(new.CurrentDirectory .. new.SelectedFile) end end, 'Save', colours.black) new.CancelButton = Button:Initialise(new.Width - 15, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle) returnFunc(new, false) end, 'Cancel', colours.black) new.GoUpButton = Button:Initialise(2, new.Height - 1, nil, nil, colours.white, new, function(self, side, x, y, toggle) local folderName = fs.getName(new.CurrentDirectory) local parentDirectory = new.CurrentDirectory:sub(1, #new.CurrentDirectory-#folderName-1) new:GoToDirectory(parentDirectory) end, 'Go Up', colours.black) new.PathTextBox = TextBox:Initialise(2, new.Height - 3, new.Width - 2, 1, new, '', colours.white, colours.black, function(key) if key == keys.enter then new.SaveButton:Click() end end) new.PathTextBox.Placeholder = 'Document Name' Current.TextInput = new.PathTextBox.TextInput new:GoToDirectory(new.CurrentDirectory) return new end, Show = function(self) Current.Window = self return self end, Close = function(self) Current.Input = nil Current.Window = nil self = nil end, GoToDirectory = function(self, path) path = TidyPath(path) self.CurrentDirectory = path self.Scroll = 0 self.Typed = false local fs = fs if OneOS then fs = OneOS.FS end self.Files = fs.list(self.CurrentDirectory) Draw() end, Flash = function(self) self.Visible = false Draw() sleep(0.15) self.Visible = true Draw() sleep(0.15) self.Visible = false Draw() sleep(0.15) self.Visible = true Draw() end, Click = function(self, side, x, y) local items = {self.SaveButton, self.CancelButton, self.PathTextBox, self.GoUpButton} local found = false for i, v in ipairs(items) do if CheckClick(v, x, y) then v:Click(side, x, y) found = true end end if not found then if y <= 11 then local files = fs.list(self.CurrentDirectory) if files[y-1] then self:GoToDirectory(self.CurrentDirectory..files[y-1]) Draw() end end end return true end } local WrapText = function(text, maxWidth) local lines = {''} for word, space in text:gmatch('(%S+)(%s*)') do local temp = lines[#lines] .. word .. space:gsub('\n','') if #temp > maxWidth then table.insert(lines, '') end if space:find('\n') then lines[#lines] = lines[#lines] .. word space = space:gsub('\n', function() table.insert(lines, '') return '' end) else lines[#lines] = lines[#lines] .. word .. space end end return lines end ButtonDialougeWindow = { X = 1, Y = 1, Width = 0, Height = 0, CursorPos = 1, Visible = true, CancelButton = nil, OkButton = nil, Lines = {}, AbsolutePosition = function(self) return {X = self.X, Y = self.Y} end, Draw = function(self) if not self.Visible then return end Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey) Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey) Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white) Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey) for i, text in ipairs(self.Lines) do Drawing.DrawCharacters(self.X + 1, self.Y + 1 + i, text, colours.black, colours.white) end self.OkButton:Draw() if self.CancelButton then self.CancelButton:Draw() end end, Initialise = function(self, title, message, okText, cancelText, returnFunc) local new = {} -- the new instance setmetatable( new, {__index = self} ) new.Width = 28 new.Lines = WrapText(message, new.Width - 2) new.Height = 5 + #new.Lines new.Return = returnFunc new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2) new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2) new.Title = title new.Visible = true new.Visible = true new.OkButton = Button:Initialise(new.Width - #okText - 2, new.Height - 1, nil, 1, nil, new, function() returnFunc(new, true) end, okText) if cancelText then new.CancelButton = Button:Initialise(new.Width - #okText - 2 - 1 - #cancelText - 2, new.Height - 1, nil, 1, nil, new, function() returnFunc(new, false) end, cancelText) end return new end, Show = function(self) Current.Window = self return self end, Close = function(self) Current.Window = nil self = nil end, Flash = function(self) self.Visible = false Draw() sleep(0.15) self.Visible = true Draw() sleep(0.15) self.Visible = false Draw() sleep(0.15) self.Visible = true Draw() end, Click = function(self, side, x, y) local items = {self.OkButton, self.CancelButton} local found = false for i, v in ipairs(items) do if CheckClick(v, x, y) then v:Click(side, x, y) found = true end end return true end } TextDialougeWindow = { X = 1, Y = 1, Width = 0, Height = 0, CursorPos = 1, Visible = true, CancelButton = nil, OkButton = nil, Lines = {}, TextInput = nil, AbsolutePosition = function(self) return {X = self.X, Y = self.Y} end, Draw = function(self) if not self.Visible then return end Drawing.DrawBlankArea(self.X + 1, self.Y+1, self.Width, self.Height, colours.grey) Drawing.DrawBlankArea(self.X, self.Y, self.Width, 1, colours.lightGrey) Drawing.DrawBlankArea(self.X, self.Y+1, self.Width, self.Height-1, colours.white) Drawing.DrawCharactersCenter(self.X, self.Y, self.Width, 1, self.Title, colours.black, colours.lightGrey) for i, text in ipairs(self.Lines) do Drawing.DrawCharacters(self.X + 1, self.Y + 1 + i, text, colours.black, colours.white) end Drawing.DrawBlankArea(self.X + 1, self.Y + self.Height - 4, self.Width - 2, 1, colours.lightGrey) Drawing.DrawCharacters(self.X + 2, self.Y + self.Height - 4, self.TextInput.Value, colours.black, colours.lightGrey) Current.CursorPos = {self.X + 2 + self.TextInput.CursorPos, self.Y + self.Height - 4} Current.CursorColour = colours.black self.OkButton:Draw() if self.CancelButton then self.CancelButton:Draw() end end, Initialise = function(self, title, message, okText, cancelText, returnFunc, numerical) local new = {} -- the new instance setmetatable( new, {__index = self} ) new.Width = 28 new.Lines = WrapText(message, new.Width - 2) new.Height = 7 + #new.Lines new.Return = returnFunc new.X = math.ceil((Drawing.Screen.Width - new.Width) / 2) new.Y = math.ceil((Drawing.Screen.Height - new.Height) / 2) new.Title = title new.Visible = true new.Visible = true new.OkButton = Button:Initialise(new.Width - #okText - 2, new.Height - 1, nil, 1, nil, new, function() if #new.TextInput.Value > 0 then returnFunc(new, true, new.TextInput.Value) end end, okText) if cancelText then new.CancelButton = Button:Initialise(new.Width - #okText - 2 - 1 - #cancelText - 2, new.Height - 1, nil, 1, nil, new, function() returnFunc(new, false) end, cancelText) end new.TextInput = TextInput:Initialise('', function(enter) if enter then new.OkButton:Click() end Draw() end, numerical) Current.Input = new.TextInput return new end, Show = function(self) Current.Window = self return self end, Close = function(self) Current.Window = nil Current.Input = nil self = nil end, Flash = function(self) self.Visible = false Draw() sleep(0.15) self.Visible = true Draw() sleep(0.15) self.Visible = false Draw() sleep(0.15) self.Visible = true Draw() end, Click = function(self, side, x, y) local items = {self.OkButton, self.CancelButton} local found = false for i, v in ipairs(items) do if CheckClick(v, x, y) then v:Click(side, x, y) found = true end end return true end } function PrintCentered(text, y) local w, h = term.getSize() x = math.ceil(math.ceil((w / 2) - (#text / 2)), 0)+1 term.setCursorPos(x, y) print(text) end function DoVanillaClose() term.setBackgroundColour(colours.black) term.setTextColour(colours.white) term.clear() term.setCursorPos(1, 1) PrintCentered("Thanks for using Ink!", (Drawing.Screen.Height/2)-1) term.setTextColour(colours.lightGrey) PrintCentered("Word Proccessor for ComputerCraft", (Drawing.Screen.Height/2)) term.setTextColour(colours.white) PrintCentered("(c) oeed 2014", (Drawing.Screen.Height/2)+3) term.setCursorPos(1, Drawing.Screen.Height) error('', 0) end function Close() if isQuitting or not Current.Document or not Current.Modified then if not OneOS then DoVanillaClose() end return true else local _w = ButtonDialougeWindow:Initialise('Quit Ink?', 'You have unsaved changes, do you want to quit anyway?', 'Quit', 'Cancel', function(window, success) if success then if OneOS then OneOS.Close(true) else DoVanillaClose() end end window:Close() Draw() end):Show() --it's hacky but it works os.queueEvent('mouse_click', 1, _w.X, _w.Y) return false end end if OneOS then OneOS.CanClose = function() return Close() end end Initialise()