--[[ This file is part of Ice Lua Components. Ice Lua Components is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Ice Lua Components is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Ice Lua Components. If not, see . ]] if common.argb_split_to_merged then argb_split_to_merged = common.argb_split_to_merged else function argb_split_to_merged(r,g,b,a) a = a or 0xFF r = math.min(math.max(0,math.floor(r+0.5)),255) g = math.min(math.max(0,math.floor(g+0.5)),255) b = math.min(math.max(0,math.floor(b+0.5)),255) a = math.min(math.max(0,math.floor(a+0.5)),255) return 256*(256*(256*a+r)+g)+b end end function abgr_split_to_merged(r,g,b,a) return argb_split_to_merged(b,g,r,a) end if common.argb_merged_to_split then argb_merged_to_split = common.argb_merged_to_split else function argb_merged_to_split(c) -- yuck local b = c % (2 ^ 8) local g = math.floor(c / (2 ^ 8) % (2 ^ 8)) local r = math.floor(c / (2 ^ 16) % (2 ^ 8)) local a = math.floor(c / (2 ^ 24)) if a < 0 then a = 0 end --print(string.format("%08X %d %d %d %d", c, r, g, b, a)) return a, r, g, b end end function recolor_component(r,g,b,mdata) for i=1,#mdata do if mdata[i].r == 0 and mdata[i].g == 0 and mdata[i].b == 0 then mdata[i].r = r mdata[i].g = g mdata[i].b = b end end end function gen_icon(mspr) local this = { ofx = mspr[1], ofy = mspr[2], } do local i local lgx, lgy = mspr[1], mspr[2] for i=3,#mspr,2 do this.ofx = math.min(this.ofx, mspr[i+0]) this.ofy = math.min(this.ofy, mspr[i+1]) lgx = math.max(lgx, mspr[i+0]) lgy = math.max(lgy, mspr[i+1]) end this.w = lgx - this.ofx + 1 this.h = lgy - this.ofy + 1 this.img = common.img_new(this.w, this.h) --print(this.w, this.h, this.ofx, this.ofy) for i=1,#mspr,2 do common.img_pixel_set(this.img, mspr[i+0]-this.ofx, mspr[i+1]-this.ofy, 0xFFFFFFFF) end end function this.blit(x, y, c, mx, my, x1, y1, x2, y2) local dx = x + this.ofx - x1 local dy = y + this.ofy - y1 local sx = 0 local sy = 0 local iw = this.w local ih = this.h if dx < 0 then local diff = 0 - dx dx = 0 sx = sx + diff iw = iw - diff end if dy < 0 then local diff = 0 - dy dy = 0 sy = sy + diff ih = ih - diff end if dx + iw >= x2-x1 then iw = (x2-x1) - dx end if dy + ih >= y2-y1 then ih = (y2-y1) - dy end if iw >= 1 and ih >= 1 then client.img_blit(this.img, dx+mx, dy+my, iw, ih, sx, sy, c) end end return this end function string.split(s, sep, plain) local start = 1 local done = false local function pass(i, j, ...) if i then local seg = s:sub(start, i - 1) start = j + 1 return seg, ... else done = true return s:sub(start) end end local result = {} while not done do if sep == '' then done = true result[#result+1]=s end result[#result+1]=pass(s:find(sep, start, plain)) end return result end -- trim the character 'sep' from the left hand side of the string function string.triml(s, sep) sep = string.byte(sep) if s == '' then return s end local pos = 1 while string.byte(s,pos)==sep and #s<=pos do pos = pos + 1 end return string.sub(s, pos+1) end -- trim the character 'sep' from the right hand side of the string function string.trimr(s, sep) sep = string.byte(sep) if s == '' then return s end local pos = #s while string.byte(s, pos)==sep and pos>=1 do pos = pos - 1 end return string.sub(s, 1, pos) end -- trim the character 'sep' from both sides of the string function string.trim(s, sep) return string.triml(string.trimr(s, sep), sep) end function parse_commandline_options(options, nocheckdash, na, nb, nc) local loose = na or {} -- loose strings, filenames, etc. local user_toggles = nb or {} -- toggle options (key is name, value is position) local user_settings = nc or {} -- key-value pairs for k, v in pairs(options) do if nocheckdash then v = "-" .. v end local setting_pair = string.split(v, "=") local first = string.byte(v,1) if first==string.byte('-') then -- we are toggling an option or setting a value if #setting_pair == 2 then -- we are setting a key to a value user_settings[string.triml(setting_pair[1], '-')]=setting_pair[2] print(string.triml(setting_pair[1], '-'),"trimmed") else user_toggles[string.triml(v, '-')]=k end elseif first == string.byte('/') then -- optional extra arg on URI -- look for a ? thing local npair = string.split(v:sub(2), "?") if npair[1] ~= "" then user_settings[" "] = npair[1] end if npair[2] then -- TODO: URI-decode local nopts = string.split(npair[2], "&") parse_commandline_options(nopts, true, loose, user_toggles, user_settings) end else -- add to the loose values loose[#loose+1] = v end end return loose, user_toggles, user_settings end --[[Create an alarm object. When run, counts down to the specified value based on the time delta passed in. time: The time limit of the alarm. Ignored with values less than 1. progress: the progress towards the time limit. active: Whether alarm is running or not. on_frame: Callback run every frame, passed in the dT of that frame. on_trigger: Callback run when alarm reaches its limit, passed in the dT of that frame. loop: Whether the alarm will continue after the first run. preserve_accumulator: Whether looping transfers overflow dT from the previous run ]] function alarm(options) local this = {} this.time = options.time or 1 this.progress = options.progress or 0 if options.active ~= nil then this.active = options.active else this.active = true end this.loop = options.loop or false this.preserve_accumulator = options.preserve_accumulator if this.preserve_accumulator == nil then this.preserve_accumulator = true end this.on_frame = options.on_frame or nil this.on_trigger = options.on_trigger or nil function this.tick(dT) if this.active then this.progress = this.progress + dT if this.on_frame ~= nil then this.on_frame(dT) end while this.progress >= this.time and this.active do if this.on_trigger ~= nil then this.on_trigger(dT) end if this.loop and this.time > 0 then if this.preserve_accumulator then this.progress = this.progress - this.time else this.progress = 0 end else this.active = false end end end end function this.restart() this.progress = 0 this.active = true end function this.time_remaining() return this.time - this.progress end return this end -- Rescale an "aval" between "amin" and "amax" to values between "bmin" and "bmax". function rescale_value(amin, amax, bmin, bmax, aval) local adist = amax - amin; local bdist = bmax - bmin; local ratio = bdist / adist; return bmin + (aval - amin) * ratio; end -- Creates a shallow copy of a table function copy_table(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in pairs(orig) do copy[orig_key] = orig_value end else -- number, string, boolean, etc copy = orig end return copy end -- GUI Events -- DELTA_TIME: -- uses the delta time passed in when listeners are pumped. -- callback passes in the dT value. GE_DELTA_TIME = 1 -- SHARED_ALARM: -- uses the scene's shared alarm, which is run at a fixed interval (default "1/60"). -- callback passes in the dT value of the shared alarm timer. GE_SHARED_ALARM = 2 -- KEY: -- User pressed or released a key. -- callback passes in {key(int), state(bool), modif(int bitmask)} GE_KEY = 3 -- TEXT: -- User submitted text to the OS by pressing key(s). -- callback passes in {text(string)} GE_TEXT = 4 -- BUTTON: -- User pressed or released a mapped button. -- callback passes in {key(int), button{name(string), desc(string)}, state(bool), modif(int bitmask)} GE_BUTTON = 5 -- MOUSE: -- Mouse movement: x, y, dx, dy. -- callback passes in {x(number), y(number), dx(number), dy(number)} GE_MOUSE = 6 -- MOUSE_BUTTON: -- Mouse button is pressed or released. -- callback passes in {button(int), down(bool)} GE_MOUSE_BUTTON = 7