Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- gui.lua
- --(( Settings ))--
- --(( Variables ))--
- local termW,termH = term.getSize()
- local pageW,pageH = 25,21
- local lockedSender = "kalle"
- local grid = {}
- --(( Functions ))--
- function updateGrid()
- -- Add lost parts
- for x = 1,termW do
- if type(grid[x]) ~= "table" then
- grid[x] = {}
- end
- for y = 1,termH do
- if type(grid[x][y]) ~= "table" then
- grid[x][y] = {
- fg = util.colorToHex(colors.white),
- bg = util.colorToHex(colors.black),
- char = " ",
- }
- end
- end
- end
- -- Remove excess
- for x in pairs(grid) do
- if type(x) ~= "number"
- or (x < 1 or x > termW) then
- grid[x] = nil
- else
- for y in pairs(grid[x]) do
- if type(y) ~= "number"
- or (y < 1 or y > termH) then
- grid[x][y] = nil
- end
- end
- end
- end
- end
- -- Get each row seperatly
- -- so you can draw it with term.blit
- function blitReadyGrid()
- local rows = {}
- -- note that I'm looping Y first
- for y = 1,termH do
- local row = {"","",""}
- for x = 1,termW do
- local pixel = getPixel(x,y)
- row[1] = row[1] .. pixel.char
- row[2] = row[2] .. pixel.fg
- row[3] = row[3] .. pixel.bg
- end
- rows[y] = row
- end
- return rows
- end
- function drawGrid()
- updateGrid()
- local rows = blitReadyGrid()
- for y,row in ipairs(rows) do
- term.setCursorPos(1,y)
- term.blit(unpack(row))
- end
- end
- function validPixel(x,y)
- return (x >= 1 and x <= termW)
- and (y >= 1 and y <= termH)
- and (x%1==0) and (y%1==0)
- end
- function getPixel( x,y )
- if validPixel(x,y) then
- return grid[x][y]
- end
- end
- function setPixel(char,x,y,fg,bg)
- if type(fg) == "number" then fg = util.colorToHex(fg) end
- if type(bg) == "number" then bg = util.colorToHex(bg) end
- if validPixel(x,y) then
- grid[x][y].char = ((char or grid[x][y].char or "") .. " "):sub(1,1)
- grid[x][y].fg = fg or grid[x][y].fg
- grid[x][y].bg = bg or grid[x][y].bg
- end
- end
- function setRect(char,x1,y1,x2,y2,fg,bg)
- for x = x1,x2 or x1 do
- for y = y1,y2 or y1 do
- setPixel(char,x,y,fg,bg)
- end
- end
- end
- function writeText(text,x,y,fg,bg)
- text = tostring(text)
- for i = 1,#text do
- setPixel(text:sub(i,i),x+i-1,y,fg,bg)
- end
- end
- function writeCentered(text,y,fg,bg)
- writeText(text,math.floor(termW/2-#text/2),y,fg,bg)
- end
- function previewMail(data)
- local tPages = mail.splitPages(mail.prepareMessage(data))
- local nPage = 1
- local pageTitle = mail.getTitle(data,nPage,#tPages)
- local scroll = -1
- local scrollbarH = 4
- local pageX = 20
- local pageY = 3
- -- height of visable area
- local viewH = 17
- local running = true
- local redraw = true
- local function changePage(newPage)
- nPage = math.max(1,math.min(#tPages, newPage))
- scroll = -1
- redraw = true
- pageTitle = mail.getTitle(data,nPage,#tPages)
- end
- local function nextPage() changePage(nPage+1) end
- local function prevPage() changePage(nPage-1) end
- local function draw()
- -- Draw header
- setRect(" ",1,1,termW,2,_,colors.cyan)
- writeCentered("Preview of",1,colors.white)
- writeCentered(pageTitle,2,colors.white)
- -- Draw background
- setRect(" ",1,3,termW,termH,_,colors.lightBlue)
- -- paper edge
- local y2 = scroll == 5 and termH-1 or termH
- setRect("|",pageX-1,3,_,y2,colors.lightBlue,colors.white)
- setRect("|",pageX+pageW,3,_,y2,colors.lightBlue,colors.white)
- -- Draw message
- local tPage = tPages[nPage]
- for nRow = 1+scroll, termH-2+scroll do
- -- filler char
- if nRow == 0 then
- -- row before page
- setRect("~",pageX,3,pageX+pageW-1,_,colors.lightBlue,colors.white)
- elseif nRow == pageH+1 then
- -- row after page
- setRect("~",pageX,termH,pageX+pageW-1,_,colors.white,colors.lightBlue)
- else
- -- get page
- sRow = tPage[nRow] or ""
- -- fill out so it redraws the entire thing
- sRow = sRow .. string.rep(" ", pageW - #sRow)
- -- write it out
- local y = pageY+nRow-scroll-1
- writeText(sRow,pageX,y,colors.gray,colors.white)
- end
- end
- -- Draw scrollbar
- local y = math.floor(pageY+(viewH-scrollbarH)*(scroll+1)/(6))
- setRect(" ", termW, 3, _, termH, _, colors.lightGray)
- setRect(" ", termW, y, _, y+scrollbarH-1, _, colors.gray)
- setPixel("^", termW, y, colors.lightGray)
- setPixel("v", termW, y+scrollbarH-1,colors.lightGray)
- -- Draw buttons
- setRect(" ", 1, pageY, 13, termH, _, colors.gray)
- writeText("Page", 2, termH-4, colors.lightGray)
- local txt = nPage.."/"..#tPages
- writeText(txt, 13-#txt, termH-4, colors.lightGray)
- writeText(" < ", 2, termH-3, colors.white, (nPage > 1) and colors.cyan or colors.lightGray)
- writeText(" > ", 8, termH-3, colors.white, (nPage < #tPages) and colors.cyan or colors.lightGray)
- writeText(" Back ", 2, termH-1, colors.white, colors.cyan)
- -- Draw to screen
- drawGrid()
- end
- local function changeScroll(delta)
- scroll = math.min(math.max(math.floor(scroll + delta),-1),pageH-viewH+1)
- redraw = true
- end
- local function handleEvents(ev,p1,p2,p3,p4,p5)
- if ev == "key" then
- if p1 == keys.down then
- changeScroll(1)
- elseif p1 == keys.up then
- changeScroll(-1)
- elseif p1 == keys.q then
- running = false
- end
- end
- if ev == "mouse_scroll" then
- changeScroll(p1)
- end
- if ev == "mouse_click" and p1 == 1 then
- if p3 == termH-3 then
- -- prev page
- if p2 >= 2 and p2 <= 6 and nPage > 1 then
- prevPage()
- end
- -- next page
- if p2 >= 8 and p2 <= 12 and nPage < #tPages then
- nextPage()
- end
- end
- -- exit
- if p3 == termH-1 and p2 >= 2 and p2 <= 12 then
- running = false
- end
- end
- end
- -- Main loop
- while running do
- if redraw then
- draw()
- end
- handleEvents(os.pullEvent())
- end
- end
- function writeMail()
- local running = true
- local redraw = true
- local selected = false
- local fields = {}
- local lshift = false
- local rshift = false
- local rctrl = false
- local lctrl = false
- local tabJump = false
- local diskAvailable = false
- local anyReceivers = false
- local function newTextArea(x1,y1,x2,y2,multiline)
- x2 = x2 or x1
- y2 = y2 or y1
- local textArea = {
- x1 = x1, x2 = x2,
- y1 = y1, y2 = y2,
- w = x2 - x1 + 1, h = y2 - y1 + 1,
- multiline = multiline,
- scrollX = 0, scrollY = 0,
- cursorX = 1, cursorY = 1,
- visableCursor = false,
- enabled = true,
- onSelect = false,
- onDeselect = false,
- lateDraw = false,
- elemType = "textArea",
- nextElem = false,
- prevElem = false,
- text = {""}
- }
- table.insert(fields,textArea)
- function textArea.destroy(self)
- for i,v in ipairs(fields) do
- if v == self then
- table.remove(fields, i)
- break
- end
- end
- end
- function textArea.localToWorld(self,x,y)
- return x + self.x1 - self.scrollX - 1, y + self.y1 - self.scrollY - 1
- end
- function textArea.worldtoLocal(self,x,y)
- return x - self.x1 + self.scrollX + 1, y - self.y1 + self.scrollY + 1
- end
- function textArea.pointInArea(self,x,y)
- return x >= self.x1 and x <= self.x2
- and y >= self.y1 and y <= self.y2
- end
- function textArea.draw(self)
- local bg = self==selected and colors.black or colors.gray
- local fg = self==selected and colors.white or colors.lightGray
- if self.elemType == "button" then
- bg = self.enabled and colors.cyan or colors.gray
- fg = self.enabled and colors.white or colors.lightGray
- end
- setRect(" ",self.x1,self.y1,self.x2,self.y2,_,bg)
- for row = 1 + self.scrollY, self.h + self.scrollY do
- if row <= #self.text then
- local x = self.x1
- local y = self.y1 + row - self.scrollY - 1
- local text = self.text[row]
- if row == 1 and self.elemType == "textArea" and not self.enabled then
- text = "(locked) "..text
- end
- writeText(text:sub(1+self.scrollX,self.scrollX+self.w),x,y,fg)
- end
- end
- if selected == self then
- local x,y = self:localToWorld(self.cursorX,self.cursorY)
- self.visableCursor = self:pointInArea(self:localToWorld(self.cursorX,self.cursorY))
- end
- end
- function textArea.setScroll(self, x,y)
- local maxW = 0
- for _,line in ipairs(self.text) do
- maxW = math.max(maxW, #line)
- end
- -- lock
- self.scrollX = math.max(math.min(maxW-1,x),0)
- self.scrollY = math.max(math.min(y,#self.text-self.h),0)
- end
- function textArea.changeScroll(self,dx,dy)
- self:setScroll(self.scrollX+dx,self.scrollY+dy)
- end
- function textArea.focusCursor(self)
- self:setScroll(
- math.min(math.max(self.scrollX,self.cursorX-self.w),self.cursorX-1),
- math.min(math.max(self.scrollY,self.cursorY-self.h),self.cursorY-1)
- )
- end
- function textArea.getText(self)
- local text = ""
- for row,str in ipairs(self.text) do
- text = text .. str
- if row < #self.text then -- not last row
- text = text .. " \n"
- end
- end
- return text
- end
- function textArea.isChecked(self)
- return self.elemType == "checkbox" and self.text[1] == "[x]"
- end
- function textArea.handleEvents(self,ev,p1,p2,p3,p4,p5)
- if not self.enabled then
- return false
- end
- if self==selected then
- if ev == "char" or ev == "paste" then
- -- Add character
- local line = self.text[self.cursorY]
- self.text[self.cursorY] = line:sub(1,self.cursorX) .. p1 .. line:sub(self.cursorX + 1,-1)
- self.cursorX = self.cursorX + 1
- self:focusCursor()
- return true
- elseif ev == "key" then
- if p1 == keys.left then
- if lctrl or rctrl then
- self:changeScroll(-1,0)
- else
- -- left
- self.cursorX = self.cursorX - 1
- if self.cursorX < 1 then
- if self.cursorY > 1 then -- not first row
- self.cursorY = self.cursorY - 1
- self.cursorX = #self.text[self.cursorY] + 1
- else
- self.cursorX = 1
- end
- end
- self:focusCursor()
- end
- return true
- elseif p1 == keys.right then
- if lctrl or rctrl then
- self:changeScroll(1,0)
- else
- -- right
- self.cursorX = self.cursorX + 1
- if self.cursorX > #self.text[self.cursorY] + 1 then
- if self.cursorY < #self.text then -- not last row
- self.cursorY = self.cursorY + 1
- self.cursorX = 1
- else
- self.cursorX = #self.text[self.cursorY] + 1
- end
- end
- self:focusCursor()
- end
- return true
- elseif p1 == keys.up then
- if lctrl or rctrl then
- self:changeScroll(0,1)
- else
- -- up
- if self.cursorY > 1 then -- not first row
- self.cursorX = math.min(self.cursorX,#self.text[self.cursorY - 1] + 1)
- self.cursorY = self.cursorY - 1
- else
- self.cursorX = 1
- end
- self:focusCursor()
- end
- return true
- elseif p1 == keys.down then
- if lctrl or rctrl then
- self:changeScroll(0,-1)
- else
- -- down
- if self.cursorY < #self.text then -- not last row
- self.cursorX = math.min(self.cursorX,#self.text[self.cursorY + 1] + 1)
- self.cursorY = self.cursorY + 1
- else
- self.cursorX = #self.text[self.cursorY] + 1
- end
- self:focusCursor()
- end
- return true
- elseif p1 == keys.backspace then
- if self.cursorX > 1 then
- -- remove a char
- local line = self.text[self.cursorY]
- self.text[self.cursorY] = line:sub(1,self.cursorX - 2) .. line:sub(self.cursorX,-1)
- self.cursorX = self.cursorX - 1
- self:focusCursor()
- return true
- else
- if self.cursorY > 1 then
- -- compress two lines
- self.text[self.cursorY - 1] = self.text[self.cursorY - 1] .. self.text[self.cursorY]
- table.remove(self.text,self.cursorY)
- self.cursorY = self.cursorY - 1
- self.cursorX = #self.text[self.cursorY] + 1
- self:focusCursor()
- return true
- end
- end
- elseif p1 == keys.delete then
- if self.cursorX < #self.text[self.cursorY]+1 then
- -- remove a char
- local line = self.text[self.cursorY]
- self.text[self.cursorY] = line:sub(1,self.cursorX - 1) .. line:sub(self.cursorX + 1,-1)
- return true
- else
- if self.cursorY < #self.text then
- -- compress two lines
- self.text[self.cursorY] = self.text[self.cursorY] .. self.text[self.cursorY + 1]
- table.remove(self.text,self.cursorY + 1)
- self:focusCursor()
- return true
- end
- end
- elseif p1 == keys.enter then
- if self.multiline then
- -- split into new line
- local line = self.text[self.cursorY]
- self.text[self.cursorY] = line:sub(1, self.cursorX - 1)
- line = line:sub(self.cursorX, -1)
- table.insert(self.text, self.cursorY + 1, line)
- self.cursorY = self.cursorY + 1
- self.cursorX = 1
- self:focusCursor()
- return true
- end
- elseif p1 == keys["end"] then
- self.cursorX = #self.text[self.cursorY] + 1
- self:focusCursor()
- return true
- elseif p1 == keys.home then
- self.cursorX = 1
- self:focusCursor()
- return true
- elseif p1 == keys.tab then
- if not tabJump then
- if rshift or lshift then
- -- prev
- if self.prevElem then
- if type(self.onDeselect) == "function" then
- self:onDeselect()
- end
- selected = self.prevElem
- if type(selected.onSelect) == "function" then
- selected:onSelect()
- end
- tabJump = true
- return true
- end
- else
- -- next
- if self.nextElem then
- if type(self.onDeselect) == "function" then
- self:onDeselect()
- end
- selected = self.nextElem
- if type(selected.onSelect) == "function" then
- selected:onSelect()
- end
- tabJump = true
- return true
- end
- end
- end
- end
- elseif ev == "mouse_scroll" then
- self:changeScroll(0,p1)
- return true
- end
- end
- if ev == "mouse_click" and p1 == 1 then
- if self:pointInArea(p2,p3) then
- if self.elemType == "textArea" then
- selected = self
- local x,y = self:worldtoLocal(p2,p3)
- self.cursorY = math.min(#self.text, y)
- self.cursorX = math.min(#self.text[self.cursorY]+1, x)
- self:focusCursor()
- elseif self.elemType == "checkbox" then
- local checked = self:isChecked()
- self.text[1] = checked and "[ ]" or "[x]"
- end
- if type(self.onSelect) == "function" then
- self:onSelect()
- end
- return true
- elseif selected == self then
- if type(self.onDeselect) == "function" then
- self:onDeselect()
- end
- selected = false
- return true
- end
- end
- return false
- end
- return textArea
- end
- local function newCheckbox( x,y,checked )
- local textArea = newTextArea(x,y,x+2,_,false)
- textArea.elemType = "checkbox"
- textArea.text[1] = checked and "[x]" or "[ ]"
- return textArea
- end
- local function newButton(x1,y1,x2,y2,str,onSelect)
- local button = newTextArea(x1,y1,x2,y2,true)
- button.elemType = "button"
- button.onSelect = onSelect
- button.enabled = true
- button.text = {}
- for i=1,button.h do
- if i == math.floor(button.h/2)+1 then
- table.insert(button.text,string.rep(" ",math.floor(button.w/2-#str/2))..str)
- else
- table.insert(button.text,"")
- end
- end
- return button
- end
- local exitField = newButton(termW,1,_,_,"X")
- local fromField = newTextArea(10,4,termW-1,_,false)
- local subjectField = newTextArea(10,6,termW-1,_,false)
- local messageField = newTextArea(10,8,termW-1,14,true)
- local previewField = newButton(termW - 14,termH-3,termW-1,_,"Preview")
- local sendField = newButton(termW - 14,termH-1,termW-1,_,"Send")
- fromField.nextElem = subjectField
- fromField.prevElem = messageField
- subjectField.nextElem = messageField
- subjectField.prevElem = fromField
- messageField.nextElem = fromField
- messageField.prevElem = subjectField
- sendField.enabled = false
- if type(lockedSender) == "string" and #lockedSender > 0 then
- fromField.enabled = false
- fromField.text[1] = lockedSender
- subjectField.prevElem = messageField
- messageField.nextElem = subjectField
- end
- local jagField = newCheckbox(10,termH - 3)
- local knautField = newCheckbox(10,termH - 2)
- local bejnoField = newCheckbox(10,termH - 1)
- local function getReceivers()
- local receivers = {}
- if jagField:isChecked() then table.insert(receivers,"jag") end
- if knautField:isChecked() then table.insert(receivers,"knaut") end
- if bejnoField:isChecked() then table.insert(receivers,"bejno") end
- return receivers
- end
- local function checkForErrors()
- local oldA,oldB = diskAvailable,anyReceivers
- diskAvailable = mail.getDrive().hasData()
- anyReceivers = #getReceivers() > 0
- sendField.enabled = diskAvailable and anyReceivers
- if diskAvailable ~= oldA or anyReceivers ~= oldB then redraw = true end
- end
- local function getMailData()
- return {
- sender = fromField:getText(),
- receivers = getReceivers(),
- message = messageField:getText(),
- subject = subjectField:getText(),
- }
- end
- previewField.onSelect = function(self)
- previewMail(getMailData())
- end
- sendField.onSelect = function(self)
- if self.enabled then
- mail.writeMail(getMailData())
- end
- end
- exitField.onSelect = function(self)
- running = false
- end
- local function draw()
- term.setCursorBlink(false)
- -- draw background
- setRect(" ",1,1,termW,2,_,colors.cyan)
- setRect(" ",1,3,termW,termH, _, colors.lightBlue)
- -- Draw text
- writeCentered("Write new mail",2,colors.white)
- writeText("From", 2, 4, colors.gray)
- writeText("Subject", 2, 6, colors.gray)
- writeText("Message", 2, 8, colors.gray)
- writeText("Send to", 2, termH - 3, colors.gray)
- writeText("- jag", 14, termH - 3, jagField:isChecked() and colors.black or colors.gray)
- writeText("- knaut", 14, termH - 2, knautField:isChecked() and colors.black or colors.gray)
- writeText("- bejno", 14, termH - 1, bejnoField:isChecked() and colors.black or colors.gray)
- if not diskAvailable then
- writeText("Requires disk in disk drive!",23,termH,colors.red)
- elseif not anyReceivers then
- writeText(" Need at least 1 receiver!",23,termH,colors.red)
- end
- -- Draw fields
- for _,field in pairs(fields) do
- if type(field.draw) == "function" then
- field:draw()
- end
- end
- for _,field in pairs(fields) do
- if type(field.lateDraw) == "function" then
- field:lateDraw()
- end
- end
- -- Draw to screen
- drawGrid()
- -- Show cursor
- if selected and selected.visableCursor then
- term.setCursorPos(selected:localToWorld(selected.cursorX,selected.cursorY))
- term.setCursorBlink(true)
- else
- term.setCursorBlink(false)
- end
- end
- local function handleEvents(ev,p1,p2,p3,p4,p5)
- checkForErrors()
- if ev == "key" then
- if p1 == keys.leftShift then lshift = true end
- if p1 == keys.rightShift then rshift = true end
- if p1 == keys.leftCtrl then lctrl = true end
- if p1 == keys.rightCtrl then rctrl = true end
- end
- if ev == "key_up" then
- if p1 == keys.leftShift then lshift = false end
- if p1 == keys.rightShift then rshift = false end
- if p1 == keys.leftCtrl then lctrl = false end
- if p1 == keys.rightCtrl then rctrl = false end
- end
- -- Update fields
- tabJump = false
- for _,field in pairs(fields) do
- if field:handleEvents(ev,p1,p2,p3,p4,p5) then
- redraw = true
- end
- end
- end
- -- Main loop
- checkForErrors()
- while running do
- if redraw then
- draw()
- redraw = false
- end
- handleEvents(os.pullEvent())
- end
- term.setBackgroundColor(colors.black)
- term.clear()
- term.setCursorPos(1,1)
- return data
- end
- -- eof
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement