From 4475d80db9a8eb0db0b7bb88cf2d76794073f46c Mon Sep 17 00:00:00 2001 From: Andrew Lee Date: Mon, 16 Nov 2020 15:31:33 -0500 Subject: Removed unnecessary stuff in programs --- Programs/Ink.bup/Contents/Info.meta | 1 - .../Ink.bup/Contents/Resources/resources_here.txt | 1 - Programs/Ink.bup/Contents/bits-UI/ink.lua | 3153 -------------------- Programs/Ink.bup/Info.meta | 1 + Programs/Ink.bup/ink.lua | 3153 ++++++++++++++++++++ 5 files changed, 3154 insertions(+), 3155 deletions(-) delete mode 100644 Programs/Ink.bup/Contents/Info.meta delete mode 100644 Programs/Ink.bup/Contents/Resources/resources_here.txt delete mode 100644 Programs/Ink.bup/Contents/bits-UI/ink.lua create mode 100644 Programs/Ink.bup/Info.meta create mode 100644 Programs/Ink.bup/ink.lua (limited to 'Programs/Ink.bup') diff --git a/Programs/Ink.bup/Contents/Info.meta b/Programs/Ink.bup/Contents/Info.meta deleted file mode 100644 index 8d1c8b6..0000000 --- a/Programs/Ink.bup/Contents/Info.meta +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Programs/Ink.bup/Contents/Resources/resources_here.txt b/Programs/Ink.bup/Contents/Resources/resources_here.txt deleted file mode 100644 index 8d1c8b6..0000000 --- a/Programs/Ink.bup/Contents/Resources/resources_here.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Programs/Ink.bup/Contents/bits-UI/ink.lua b/Programs/Ink.bup/Contents/bits-UI/ink.lua deleted file mode 100644 index 49f6119..0000000 --- a/Programs/Ink.bup/Contents/bits-UI/ink.lua +++ /dev/null @@ -1,3153 +0,0 @@ -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() \ No newline at end of file diff --git a/Programs/Ink.bup/Info.meta b/Programs/Ink.bup/Info.meta new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/Programs/Ink.bup/Info.meta @@ -0,0 +1 @@ + diff --git a/Programs/Ink.bup/ink.lua b/Programs/Ink.bup/ink.lua new file mode 100644 index 0000000..49f6119 --- /dev/null +++ b/Programs/Ink.bup/ink.lua @@ -0,0 +1,3153 @@ +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() \ No newline at end of file -- cgit v1.2.3