From 7653257a7f985f511a5c4d366c1a1df3a1377949 Mon Sep 17 00:00:00 2001 From: Robert Jelic <36573031+NoryiE@users.noreply.github.com> Date: Fri, 30 Sep 2022 23:38:28 +0200 Subject: [PATCH] New Features - Bimg images are now stretchable - Label autosize automatically calculates the height - added onRelease event --- Basalt/Object.lua | 21 +++++++ Basalt/libraries/bimgLibrary.lua | 10 ++++ Basalt/libraries/images.lua | 25 ++++++++ Basalt/libraries/utils.lua | 98 ++++++++++++++++++++++++++++++++ Basalt/objects/Graphic.lua | 27 +++++++-- Basalt/objects/Image.lua | 26 +++++++-- Basalt/objects/Label.lua | 39 ++++++++++++- 7 files changed, 231 insertions(+), 15 deletions(-) diff --git a/Basalt/Object.lua b/Basalt/Object.lua index e986dd3..bf66510 100644 --- a/Basalt/Object.lua +++ b/Basalt/Object.lua @@ -15,6 +15,7 @@ return function(name) local isVisible = true local initialized = false local isHovered = false + local isClicked = false local shadow = false local borderColors = { @@ -586,6 +587,20 @@ return function(name) return self end; + onRelease = function(self, ...) + for _,v in pairs(table.pack(...))do + if(type(v)=="function")then + self:registerEvent("mouse_release", v) + end + end + if(self.parent~=nil)then + self.parent:addEvent("mouse_click", self) + activeEvents["mouse_click"] = true + self.parent:addEvent("mouse_up", self) + activeEvents["mouse_up"] = true + end + return self + end; onScroll = function(self, ...) for _,v in pairs(table.pack(...))do @@ -770,6 +785,7 @@ return function(name) if(self.parent~=nil)then self.parent:setFocusedObject(self) end + isClicked = true isDragging = true dragStartX, dragStartY = x, y return true @@ -779,6 +795,11 @@ return function(name) mouseUpHandler = function(self, button, x, y) isDragging = false + if(isClicked)then + local objX, objY = self:getAbsolutePosition() + local val = eventSystem:sendEvent("mouse_release", self, "mouse_release", button, x - (objX-1), y - (objY-1)) + isClicked = false + end if(self:isCoordsInObject(x, y))then local objX, objY = self:getAbsolutePosition() local val = eventSystem:sendEvent("mouse_up", self, "mouse_up", button, x - (objX-1), y - (objY-1)) diff --git a/Basalt/libraries/bimgLibrary.lua b/Basalt/libraries/bimgLibrary.lua index 80737a5..559edf7 100644 --- a/Basalt/libraries/bimgLibrary.lua +++ b/Basalt/libraries/bimgLibrary.lua @@ -101,6 +101,16 @@ return function() w, h = _w, _h end, + setBimgData = function(data) + w, h = 0, 0 + for k,v in pairs(data[1])do + t[k], fg[k], bg[k] = v[1], v[2], v[3] + if(#v[1] > w)then w = #v[1] end + end + h = #data[1] + recalculateSize() + end, + getBimgData = function() local data = {} for k,v in pairs(t)do diff --git a/Basalt/libraries/images.lua b/Basalt/libraries/images.lua index 1fa7939..6f02dda 100644 --- a/Basalt/libraries/images.lua +++ b/Basalt/libraries/images.lua @@ -1,3 +1,5 @@ +local sub = string.sub + local function loadNFP(path) return paintutils.loadImage(path), "nfp" end @@ -24,9 +26,32 @@ local function loadImage(path, f) -- ... end +local function resizeBIMG(source, w, h) + local oW, oH = #source[1][1][1], #source[1] + local xRatio, yRatio = oW / w, oH / h + local newImg = {{}} + for k,v in pairs(source)do if(k~=1)then newImg[k] = v end end + local img = source[1] + for y=1, h do + local xT,xFG,xBG = "","","" + local yR = math.floor(y / h * oH + 0.5) + if(img[yR]~=nil)then + for x=1, w do + local xR = math.floor(x / w * oW + 0.5) + xT = xT..sub(img[yR][1], xR,xR) + xFG = xFG..sub(img[yR][2], xR,xR) + xBG = xBG..sub(img[yR][3], xR,xR) + end + table.insert(newImg[1], {xT, xFG, xBG}) + end + end + return newImg +end + return { loadNFP = loadNFP, loadBIMG = loadBIMG, loadImage = loadImage, + resizeBIMG = resizeBIMG, } \ No newline at end of file diff --git a/Basalt/libraries/utils.lua b/Basalt/libraries/utils.lua index f9844ce..ed1ebb0 100644 --- a/Basalt/libraries/utils.lua +++ b/Basalt/libraries/utils.lua @@ -1,3 +1,5 @@ +local sub = string.sub + local splitString = function(str, sep) if sep == nil then sep = "%s" @@ -9,6 +11,74 @@ local splitString = function(str, sep) return t end +local relations = {[0] = {8, 4, 3, 6, 5}, {4, 14, 8, 7}, {6, 10, 8, 7}, {9, 11, 8, 0}, {1, 14, 8, 0}, {13, 12, 8, 0}, {2, 10, 8, 0}, {15, 8, 10, 11, 12, 14}, + {0, 7, 1, 9, 2, 13}, {3, 11, 8, 7}, {2, 6, 7, 15}, {9, 3, 7, 15}, {13, 5, 7, 15}, {5, 12, 8, 7}, {1, 4, 7, 15}, {7, 10, 11, 12, 14}} + +local colourNum, exponents, colourChar = {}, {}, {} +for i = 0, 15 do exponents[2^i] = i end +do + local hex = "0123456789abcdef" + for i = 1, 16 do + colourNum[hex:sub(i, i)] = i - 1 + colourNum[i - 1] = hex:sub(i, i) + colourChar[hex:sub(i, i)] = 2 ^ (i - 1) + colourChar[2 ^ (i - 1)] = hex:sub(i, i) + + local thisRel = relations[i - 1] + for i = 1, #thisRel do thisRel[i] = 2 ^ thisRel[i] end + end +end + +local function getBestColourMatch(usage) + local lastCol = relations[exponents[usage[#usage][1]]] + + for j = 1, #lastCol do + local thisRelation = lastCol[j] + for i = 1, #usage - 1 do if usage[i][1] == thisRelation then return i end end + end + + return 1 +end + +local function colsToChar(pattern, totals) + if not totals then + local newPattern = {} + totals = {} + for i = 1, 6 do + local thisVal = pattern[i] + local thisTot = totals[thisVal] + totals[thisVal], newPattern[i] = thisTot and (thisTot + 1) or 1, thisVal + end + pattern = newPattern + end + + local usage = {} + for key, value in pairs(totals) do usage[#usage + 1] = {key, value} end + + if #usage > 1 then + -- Reduce the chunk to two colours: + while #usage > 2 do + table.sort(usage, function (a, b) return a[2] > b[2] end) + local matchToInd, usageLen = getBestColourMatch(usage), #usage + local matchFrom, matchTo = usage[usageLen][1], usage[matchToInd][1] + for i = 1, 6 do if pattern[i] == matchFrom then + pattern[i] = matchTo + usage[matchToInd][2] = usage[matchToInd][2] + 1 + end end + usage[usageLen] = nil + end + + -- Convert to character. Adapted from oli414's function: + -- http://www.computercraft.info/forums2/index.php?/topic/25340-cc-176-easy-drawing-characters/ + local data = 128 + for i = 1, #pattern - 1 do if pattern[i] ~= pattern[6] then data = data + 2^(i-1) end end + return string.char(data), colourChar[usage[1][1] == pattern[6] and usage[2][1] or usage[1][1]], colourChar[pattern[6]] + else + -- Solid colour character: + return "\128", colourChar[pattern[1]], colourChar[pattern[1]] + end +end + return { getTextHorizontalAlign = function(text, width, textAlign, replaceChar) text = string.sub(text, 1, width) @@ -117,4 +187,32 @@ uuid = function() end return uuid() end, + +shrink = function(image, bgCol) + local results, width, height, bgCol = {{}, {}, {}}, 0, #image + #image % 3, bgCol or colours.black + for i = 1, #image do if #image[i] > width then width = #image[i] end end + + for y = 0, height - 1, 3 do + local cRow, tRow, bRow, counter = {}, {}, {}, 1 + + for x = 0, width - 1, 2 do + -- Grab a 2x3 chunk: + local pattern, totals = {}, {} + + for yy = 1, 3 do for xx = 1, 2 do + pattern[#pattern + 1] = (image[y + yy] and image[y + yy][x + xx]) and (image[y + yy][x + xx] == 0 and bgCol or image[y + yy][x + xx]) or bgCol + totals[pattern[#pattern]] = totals[pattern[#pattern]] and (totals[pattern[#pattern]] + 1) or 1 + end end + + cRow[counter], tRow[counter], bRow[counter] = colsToChar(pattern, totals) + counter = counter + 1 + end + + results[1][#results[1] + 1], results[2][#results[2] + 1], results[3][#results[3] + 1] = table.concat(cRow), table.concat(tRow), table.concat(bRow) + end + + results.width, results.height = #results[1][1], #results[1] + + return results +end, } \ No newline at end of file diff --git a/Basalt/objects/Graphic.lua b/Basalt/objects/Graphic.lua index d3d9ace..f8e2991 100644 --- a/Basalt/objects/Graphic.lua +++ b/Basalt/objects/Graphic.lua @@ -2,6 +2,7 @@ local Object = require("Object") local tHex = require("tHex") local xmlValue = require("utils").getValueFromXML local bimgLib = require("bimgLibrary") +local images = require("images") local sub,len,max,min = string.sub,string.len,math.max,math.min @@ -46,7 +47,7 @@ return function(name) x = _x or x y = _y or y imgData.blit(text, fg, bg, x, y) - bimg = imgData.getBimgData()[1] + bimg = imgData.getBimgData() self:updateDraw() return self end, @@ -55,7 +56,7 @@ return function(name) x = _x or x y = _y or y imgData.text(text, x, y) - bimg = imgData.getBimgData()[1] + bimg = imgData.getBimgData() self:updateDraw() return self end, @@ -64,7 +65,7 @@ return function(name) x = _x or x y = _y or y imgData.bg(bg, x, y) - bimg = imgData.getBimgData()[1] + bimg = imgData.getBimgData() self:updateDraw() return self end, @@ -73,7 +74,7 @@ return function(name) x = _x or x y = _y or y imgData.fg(fg, x, y) - bimg = imgData.getBimgData()[1] + bimg = imgData.getBimgData() self:updateDraw() return self end, @@ -84,11 +85,25 @@ return function(name) setImageSize = function(self, w, h) imgData.setSize(w, h) - bimg = imgData.getBimgData()[1] + bimg = imgData.getBimgData() self:updateDraw() return self end, + resizeImage = function(self, w, h) + bimg = images.resizeBIMG(bimg, w, h) + imgData.setBimgData(bimg) + return self + end, + + loadImage = function(self, path, _format) + if(fs.exists(path))then + bimg = images.loadBIMG(path, _format) + imgData.setBimgData(bimg) + end + return self + end, + clear = function(self) imgData = bimgLib() bimg = nil @@ -106,7 +121,7 @@ return function(name) local obx, oby = self:getAnchorPosition() local w,h = self:getSize() if(bimg~=nil)then - for k,v in pairs(bimg)do + for k,v in pairs(bimg[1])do if(k<=h-yOffset)and(k+yOffset>=1)then self.parent:blit(obx+xOffset, oby+k-1+yOffset, v[1], v[2], v[3]) end diff --git a/Basalt/objects/Image.lua b/Basalt/objects/Image.lua index 3806dce..1cfd17b 100644 --- a/Basalt/objects/Image.lua +++ b/Basalt/objects/Image.lua @@ -2,12 +2,13 @@ local Object = require("Object") local xmlValue = require("utils").getValueFromXML local images = require("images") -local unpack = table.unpack +local unpack,sub = table.unpack,string.sub return function(name) -- Image local base = Object(name) local objectType = "Image" base:setZIndex(2) + local originalImage local image local format = "nfp" @@ -20,7 +21,8 @@ return function(name) end; loadImage = function(self, path, f) - image, _format = images.loadImage(path, f) + originalImage, _format = images.loadImage(path, f) + image = originalImage if(_format~=nil)then format = _format end @@ -29,7 +31,7 @@ return function(name) end; setImage = function(self, data, _format) - iamge = data + originalImage = data format = _format end, @@ -37,6 +39,18 @@ return function(name) return image end, + getImageSize = function(self) + return #image[1][1][1], #image[1] + end, + + resizeImage = function(self, w, h) + if(format=="bimg")then + image = images.resizeBIMG(originalImage, w, h) + self:updateDraw() + end + return self + end, + setValuesByXMLData = function(self, data) base.setValuesByXMLData(self, data) if(xmlValue("path", data)~=nil)then self:loadImage(xmlValue("path", data)) end @@ -53,9 +67,9 @@ return function(name) elseif(format=="bimg")then for y,v in ipairs(image[1])do local t, f, b = unpack(v) - t = t:sub(1,w) - f = f:sub(1,w) - b = b:sub(1,w) + t = sub(t, 1,w) + f = sub(f, 1,w) + b = sub(b, 1,w) self.parent:blit(obx, oby+y-1, t, f, b) if(y==h)then break end end diff --git a/Basalt/objects/Label.lua b/Basalt/objects/Label.lua index 28e28bd..433beb5 100644 --- a/Basalt/objects/Label.lua +++ b/Basalt/objects/Label.lua @@ -31,7 +31,12 @@ return function(name) text = tostring(text) base:setValue(text) if (autoSize) then - base.width = text:len() + if(text:len()+self:getX()>self.parent:getWidth())then + local newW = self.parent:getWidth() - self:getX() + base.setSize(self, newW, #createText(text, newW)) + else + base.setSize(self, text:len(), 1) + end end self:updateDraw() return self @@ -86,6 +91,22 @@ return function(name) return self end; + eventHandler = function(self, event) + if(event=="basalt_resize")then + if (autoSize) then + local text = self:getValue() + if(text:len()+self:getX()>self.parent:getWidth())then + local newW = self.parent:getWidth() - self:getX() + base.setSize(self, newW, #createText(text, newW)) + else + base.setSize(self, text:len(), 1) + end + else + --self.parent:removeEvent("other_event", self) + end + end + end, + draw = function(self) if (base.draw(self)) then if (self.parent ~= nil) then @@ -96,10 +117,21 @@ return function(name) if not(autoSize)then local text = createText(self:getValue(), self:getWidth()) for k,v in pairs(text)do - self.parent:writeText(obx, oby+k-1, v, self.bgColor, self.fgColor) + if(k<=h)then + self.parent:writeText(obx, oby+k-1, v, self.bgColor, self.fgColor) + end end else - self.parent:writeText(obx, oby, self:getValue(), self.bgColor, self.fgColor) + if(#self:getValue()+obx>self.parent:getWidth())then + local text = createText(self:getValue(), self:getWidth()) + for k,v in pairs(text)do + if(k<=h)then + self.parent:writeText(obx, oby+k-1, v, self.bgColor, self.fgColor) + end + end + else + self.parent:writeText(obx, oby, self:getValue(), self.bgColor, self.fgColor) + end end else local tData = bigFont(fontsize, self:getValue(), self.fgColor, self.bgColor or colors.lightGray) @@ -127,6 +159,7 @@ return function(name) if(self.parent.bgColor==colors.black)and(self.fgColor==colors.black)then self.fgColor = colors.lightGray end + self.parent:addEvent("other_event", self) end end