diff --git a/mess/tmpc.lua b/mess/tmpc.lua index 1000a82..83b64e9 100644 --- a/mess/tmpc.lua +++ b/mess/tmpc.lua @@ -28,53 +28,12 @@ settings.define("mplayer.colors.status", { type = number }) - - -local mplayer = { - colors = { - bg = colors.black, - fg = colors.white, - cursor = colors.blue, - current = colors.yellow, - status = colors.lime - }, - songs = {}, - scroll = 0, - cursor = 1, - pos = 0, - size = 360000 * 64, - state = "PLAYING", - currentSong = 0, - statusLineScroll = 0, - highlightedLineScroll = 0, -} - -local function centerText(y, bg, fg, txt) - local w, _ = term.getSize() - local x = math.max(1, math.floor((w - #txt) / 2)) - term.setCursorPos(x, y) - term.setBackgroundColor(bg) - term.setTextColor(fg) - term.clearLine() - term.write(txt) -end - local function time2str(ti) ti = math.floor(ti) local m, s = math.floor(ti / 60), ti % 60 return string.format("%02d:%02d", m, s) end -local function setupTerminal() - for k, v in pairs(mplayer.colors) do - term.setPaletteColor(v, settings.get("mplayer.colors." .. k)) - end - term.setCursorPos(1, 1) - term.setBackgroundColor(mplayer.colors.bg) - term.setTextColor(mplayer.colors.fg) - term.clear() -end - local function read32(fp) local v = 0 for i = 1, 4 do @@ -84,15 +43,218 @@ local function read32(fp) return v end +local help = {} + +for line in ([[# Movement: +-- + Up k : Move cursor up + Down j : Move cursor down + H : Move cursor to the top of screen + L : Move cursor to the bottom of screen + PageUp : Page up + PageDown : Page down + + Tab : Next screen + Shift+Tab : Previous screen + + 1 F1 h : Help screen (this one) + 2 F2 : Songs list + 3 F3 : Options screen + +# Global: +-- + s : Stop and seek to the beginning + p : Pause/resume + < : Next track + > : Previous track + f : Seek forward + b : Seek backward + Left - : Decrease volume + Right + : Increase volume + +# List screen: +-- + Enter : Play + Ctrl+l : Center + l : Jump to current track + +]]):gmatch("[^\n]+") do + table.insert(help, line) +end + + +local mplayer = { + colors = { + bg = colors.black, + fg = colors.white, + cursor = colors.blue, + current = colors.yellow, + status = colors.lime + }, + heldKeys = {}, + screens = { + { + title = "Help", + scroll = 0, + render = function(self) + local tw, th = term.getSize() + for i = 1, th - 3 do + local line = help[i + self.screens[1].scroll] or "~" + term.setCursorPos(1, i + 1) + term.clearLine() + if line:sub(1, 1) == "~" then + term.setTextColor(self.colors.cursor) + elseif line:sub(1, 1) == "#" then + term.setTextColor(self.colors.current) + elseif line:sub(1, 2) == "--" then + term.setTextColor(self.colors.status) + term.write(("-"):rep(tw - 2)) + else + term.setTextColor(self.colors.fg) + end + term.write(line) + end + end, + handleKey = function(self, key, repeating) + local _, th = term.getSize() + if key == keys.down or key == keys.j then + self.screens[1].handleScroll(self, 1) + elseif key == keys.up or key == keys.k then + self.screens[1].handleScroll(self, -1) + elseif key == keys.pageDown then + self.screens[1].handleScroll(self, th - 3) + elseif key == keys.pageUp then + self.screens[1].handleScroll(self, -(th - 3)) + end + end, + handleScroll = function(self, direction, x, y) + local _, th = term.getSize() + self.screens[1].scroll = math.max(0, math.min(th - 1, self.screens[1].scroll + direction)) + end, + }, + { + title = "List", + scroll = 0, + cursor = 1, + textScroll = 0, + render = function(self) + local tw, th = term.getSize() + for i = 1, th - 3 do + local song = self.songs[i + self.screens[2].scroll] + local isCurrent = (i + self.screens[2].scroll) == self.currentSong + local isHovered = (i + self.screens[2].scroll) == self.screens[2].cursor + term.setCursorPos(1, i + 1) + local bg, fg = self.colors.bg, (isCurrent and self.colors.current or self.colors.fg) + if isHovered then bg, fg = fg, bg end + term.setBackgroundColor(bg) + term.setTextColor(fg) + term.clearLine() + if song then + local timeString = " ["..time2str(song.length / 6000) .. "]" + local w = tw - #timeString + if #song.title <= w then + term.write(song.title) + else + local off = isHovered and ((self.screens[2].textScroll % (#song.title + 5)) + 1) or 1 + local txt = song.title .. " ::: " .. song.title + term.write(txt:sub(off, off + w - 1)) + end + term.setCursorPos(tw - #timeString + 1, i + 1) + term.write(timeString) + end + end + end, + handleKey = function(self, key, repeating) + local _, th = term.getSize() + if key == keys.down or key == keys.j then + self.screens[2].handleScroll(self, 1) + elseif key == keys.up or key == keys.k then + self.screens[2].handleScroll(self, -1) + elseif key == keys.pageDown then + self.screens[2].handleScroll(self, th - 3) + elseif key == keys.pageUp then + self.screens[2].handleScroll(self, -(th - 3)) + elseif key == keys.enter then + self.pos = self.songs[self.screens[2].cursor].offset + self.currentSong = self.screens[2].cursor + end + end, + handleScroll = function(self, direction, x, y) + local _, th = term.getSize() + self.screens[2].cursor = math.max(1, math.min(#self.songs, self.screens[2].cursor + direction)) + if self.screens[2].scroll + 1 > self.screens[2].cursor then + self.screens[2].scroll = self.screens[2].cursor - 1 + end + local maxi = self.screens[2].scroll + th - 3 + if self.screens[2].cursor > maxi then + self.screens[2].scroll = self.screens[2].cursor - (th - 3) + end + self.screens[2].textScroll = 0 + end, + }, + { + title = "Settings", + scroll = 0, + cursor = 1, + render = function(self) + term.clear() + term.write(string.format("opt = %d, scroll = %d", self.screens[3].cursor, self.screens[3].scroll)) + end, + handleKey = function(self, key, repeating) + local _, th = term.getSize() + if key == keys.down or key == keys.j then + self.screens[3].handleScroll(self, 1) + elseif key == keys.up or key == keys.k then + self.screens[3].handleScroll(self, -1) + elseif key == keys.pageDown then + self.screens[3].handleScroll(self, th - 3) + elseif key == keys.pageUp then + self.screens[3].handleScroll(self, -(th - 3)) + end + end, + handleScroll = function(self, direction, x, y) + local _, th = term.getSize() + self.screens[3].cursor = math.max(1, math.min(20, self.screens[3].cursor + direction)) + if self.screens[3].scroll + 1 > self.screens[3].cursor then + self.screens[3].scroll = self.screens[3].cursor - 1 + end + local maxi = self.screens[3].scroll + th - 3 + if self.screens[3].cursor > maxi then + self.screens[3].scroll = self.screens[3].cursor - (th - 3) + end + end + } + }, + songs = {}, + pos = 0, + size = 360000 * 64, + state = "PLAYING", + currentSong = 0, + statusLineScroll = 0, + currentScreen = 2, +} + +local function setupTerminal() + for k, v in pairs(mplayer.colors) do + term.setPaletteColor(v, settings.get("mplayer.colors." .. k)) + end + term.setCursorPos(1, 1) + term.setBackgroundColor(mplayer.colors.bg) + term.setTextColor(mplayer.colors.fg) + term.clear() +end + local fp = io.open("noita.dfpwm", "rb") if fp ~= nil then for i = 1, 24 do - mplayer.songs[i] = {} - mplayer.songs[i].offset = read32(fp) - mplayer.songs[i].length = read32(fp) + local offset = read32(fp) + local length = read32(fp) local title = fp:read(117) local zero = math.min(64, title:find("\x00") or 0) - mplayer.songs[i].title = title:sub(1, zero) + title = title:sub(1, zero) + if length > 0 and offset > 0 then + mplayer.songs[i] = { offset = offset, length = length, title = title } + end end fp:close() end @@ -102,24 +264,21 @@ setupTerminal() local tw, th = term.getSize() parallel.waitForAny( function() - term.setCursorPos(1, 1) - term.clear() - print(" 0123456789abcdef") - term.write("0 ") - for i = 1, 255 do - if (i % 16) == 0 then term.write(string.format("%x ", i / 16)) end - term.write(string.char(i)) - if (i % 16) == 15 then print() end - end while true do + -- Current screen + term.setCursorPos(1, 2) + mplayer.screens[mplayer.currentScreen].render(mplayer) -- Top bar - - -- Songs list - for i = 1, th - 3 do - + term.setCursorPos(1, 1) + for i, screen in ipairs(mplayer.screens) do + term.setTextColor(mplayer.colors[i == mplayer.currentScreen and "bg" or "fg"]) + term.setBackgroundColor(mplayer.colors[i == mplayer.currentScreen and "fg" or "bg"]) + term.write(" "..i..":"..screen.title.." ") end + term.setBackgroundColor(mplayer.colors.bg) + local title, time, duration = "Whatever is on the tape", mplayer.pos / 6000, mplayer.size / 6000 if mplayer.currentSong ~= 0 then local song = mplayer.songs[mplayer.currentSong] @@ -165,21 +324,60 @@ function() end, function() local pretty = require("cc.pretty") + local tw, th = term.getSize() while true do local _evd = { os.pullEvent() } local ev, evd = table.remove(_evd, 1), _evd + if ev == "key" then + mplayer.heldKeys[evd[1]] = evd[2] + elseif ev == "key_up" then + mplayer.heldKeys[evd[1]] = nil + end + if ev == "key_up" and evd[1] == keys.q then break + elseif ev == "key" and (evd[1] == keys.one or evd[1] == keys.f1) then + mplayer.currentScreen = 1 + elseif ev == "key" and (evd[1] == keys.two or evd[1] == keys.f2) then + mplayer.currentScreen = 2 + elseif ev == "key" and (evd[1] == keys.three or evd[1] == keys.f3) then + mplayer.currentScreen = 3 elseif ev == "key" and evd[1] == keys.f then mplayer.pos = mplayer.pos + 3000 elseif ev == "key" and evd[1] == keys.b then mplayer.pos = mplayer.pos - 3000 + elseif ev == "key" and evd[1] == keys.tab then + local dir = ((mplayer.heldKeys[keys.leftShift] ~= nil) or (mplayer.heldKeys[keys.rightShift] ~= nil)) and -1 or 1 + mplayer.currentScreen = ((mplayer.currentScreen - 1 + #mplayer.screens + dir)) % #mplayer.screens + 1 + elseif ev == "key" then + mplayer.screens[mplayer.currentScreen].handleKey(mplayer, evd[1], evd[2]) elseif ev == "mouse_scroll" then local dir, x, y = table.unpack(evd) + mplayer.screens[mplayer.currentScreen].handleScroll(mplayer, dir, x, y) elseif ev == "song_change" then mplayer.statusLineScroll = 0 + elseif (ev == "mouse_click" or ev == "mouse_drag") and evd[3] == th - 1 then + local p = (evd[2] - 1) / tw + local song = mplayer.songs[mplayer.currentSong] + if song ~= nil then + mplayer.pos = song.offset + math.floor(song.length * p) + else + mplayer.pos = math.floor(p * mplayer.size) + end + elseif (ev == "mouse_click" or ev == "mouse_drag") and evd[3] == 1 then + local cx, x = 1, evd[2] + for i, screen in ipairs(mplayer.screens) do + local caption = " "..i..""..screen.title.." " + if x >= cx and x <= (cx + #caption) then + mplayer.currentScreen = i + break + end + cx = cx + #caption + end + elseif ev == "term_resize" then + tw, th = term.getSize() elseif ev ~= "timer" then - local m = term.redirect(term.native()) + local m = term.redirect(peripheral.wrap("right")) io.write(ev .. " ") pretty.print(pretty.pretty(evd)) term.redirect(m) @@ -189,7 +387,8 @@ end, function() while true do mplayer.statusLineScroll = mplayer.statusLineScroll + 1 - os.sleep(0.5) + mplayer.screens[2].textScroll = mplayer.screens[2].textScroll + 1 + os.sleep(0.25) end end, function()