diff --git a/filechooser.lua b/filechooser.lua index ae5104c82..bd2fedbbc 100644 --- a/filechooser.lua +++ b/filechooser.lua @@ -2,6 +2,8 @@ require "rendertext" require "keys" require "graphics" require "fontchooser" +require "filesearcher" +require "inputbox" FileChooser = { -- Class vars: @@ -35,6 +37,7 @@ function FileChooser:readdir() table.insert(self.files, f) end end + --@TODO make sure .. is sortted to the first item 16.02 2012 table.sort(self.dirs) table.sort(self.files) end @@ -151,6 +154,7 @@ function FileChooser:choose(ypos, height) end local ev = input.waitForEvent() if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then + print("key code:"..ev.code) if ev.code == KEY_FW_UP then if self:rotationMode() == 0 then prevItem() @@ -183,6 +187,24 @@ function FileChooser:choose(ypos, height) clearglyphcache() end pagedirty = true + elseif ev.code == KEY_S then + -- invoke search input + keywords = InputBox:input(height-100, 100, "Search:") + if keywords then -- display search result according to keywords + --[[ + ---------------------------------------------------------------- + || uncomment following line and set the correct path if you want + || to test search feature in EMU mode + ---------------------------------------------------------------- + --]] + --FileSearcher:init("/home/dave/documents/kindle/backup/documents") + FileSearcher:init() + file = FileSearcher:choose(ypos, height, keywords) + if file then + return file + end + end + pagedirty = true elseif ev.code == KEY_PGFWD then if self.page < (self.items / perpage) then if self.current + self.page*perpage > self.items then diff --git a/filesearcher.lua b/filesearcher.lua new file mode 100644 index 000000000..d59e0cd49 --- /dev/null +++ b/filesearcher.lua @@ -0,0 +1,232 @@ +require "rendertext" +require "keys" +require "graphics" + +FileSearcher = { + -- font for displaying file/dir names + face = freetype.newBuiltinFace("sans", 25), + fhash = "s25", + -- font for page title + tface = freetype.newBuiltinFace("Helvetica-BoldOblique", 32), + tfhash = "hbo32", + -- font for paging display + sface = freetype.newBuiltinFace("sans", 16), + sfhash = "s16", + -- title height + title_H = 45, + -- spacing between lines + spacing = 40, + -- foot height + foot_H = 27, + + -- state buffer + dirs = {}, + files = {}, + result = {}, + items = 0, + page = 0, + current = 1, + oldcurrent = 1, +} + +function FileSearcher:readdir() + self.dirs = {self.path} + self.files = {} + while #self.dirs ~= 0 do + new_dirs = {} + -- handle each dir + for __, d in pairs(self.dirs) do + -- handle files in d + for f in lfs.dir(d) do + if lfs.attributes(self.path.."/"..f, "mode") == "directory" + and f ~= "." and f~= ".." and not string.match(f, "^%.[^.]") then + table.insert(new_dirs, d.."/"..f) + elseif string.match(f, ".+%.[pP][dD][fF]$") then + file_entry = {dir=d, name=f,} + table.insert(self.files, file_entry) + --print("file:"..d.."/"..f) + end + end + end + self.dirs = new_dirs + end +end + +function FileSearcher:setPath(newPath) + self.path = newPath + self:readdir() + self.items = #self.files + --@TODO check none found 19.02 2012 + if self.items == 0 then + return nil + end + self.page = 1 + self.current = 1 + return true +end + +function FileSearcher:setSearchResult(keywords) + self.result = {} + if keywords == " " then -- one space to show all files + self.result = self.files + else + for __,f in pairs(self.files) do + if string.find(string.lower(f.name), keywords) then + table.insert(self.result, f) + end + end + end + self.items = #self.result + self.page = 1 + self.current = 1 +end + +function FileSearcher:init(search_path) + if search_path then + self:setPath(search_path) + else + self:setPath("/mnt/us/documents") + end +end + + +function FileSearcher:choose(ypos, height, keywords) + local perpage = math.floor(height / self.spacing) - 2 + local pagedirty = true + local markerdirty = false + + local prevItem = function () + if self.current == 1 then + if self.page > 1 then + self.current = perpage + self.page = self.page - 1 + pagedirty = true + end + else + self.current = self.current - 1 + markerdirty = true + end + end + + local nextItem = function () + if self.current == perpage then + if self.page < (self.items / perpage) then + self.current = 1 + self.page = self.page + 1 + pagedirty = true + end + else + if self.page ~= math.floor(self.items / perpage) + 1 + or self.current + (self.page-1)*perpage < self.items then + self.current = self.current + 1 + markerdirty = true + end + end + end + + self:setSearchResult(keywords) + + while true do + if pagedirty then + markerdirty = true + fb.bb:paintRect(0, ypos, fb.bb:getWidth(), height, 0) + + -- draw menu title + renderUtf8Text(fb.bb, 30, ypos + self.title_H, self.tface, self.tfhash, + "Search Result for: "..keywords, true) + + -- draw results + local c + if self.items == 0 then -- nothing found + y = ypos + self.title_H + self.spacing * 2 + renderUtf8Text(fb.bb, 20, y, self.face, self.fhash, + "Sorry, your keyword did not match any documents.", true) + renderUtf8Text(fb.bb, 20, y + self.spacing, self.face, self.fhash, + "Please try a different keyword.", true) + markerdirty = false + else -- found something, draw it + for c = 1, perpage do + local i = (self.page - 1) * perpage + c + if i <= self.items then + y = ypos + self.title_H + (self.spacing * c) + renderUtf8Text(fb.bb, 50, y, self.face, self.fhash, + self.result[i].name, true) + end + end + end + + -- draw footer + y = ypos + self.title_H + (self.spacing * perpage) + self.foot_H + x = (fb.bb:getWidth() / 2) - 50 + all_page = (math.floor(self.items / perpage)+1) + renderUtf8Text(fb.bb, x, y, self.sface, self.sfhash, + "Page "..self.page.." of "..all_page, true) + end + + if markerdirty then + if not pagedirty then + if self.oldcurrent > 0 then + y = ypos + self.title_H + (self.spacing * self.oldcurrent) + 10 + fb.bb:paintRect(30, y, fb.bb:getWidth() - 60, 3, 0) + fb:refresh(1, 30, y, fb.bb:getWidth() - 60, 3) + end + end + -- draw new marker line + y = ypos + self.title_H + (self.spacing * self.current) + 10 + fb.bb:paintRect(30, y, fb.bb:getWidth() - 60, 3, 15) + if not pagedirty then + fb:refresh(1, 30, y, fb.bb:getWidth() - 60, 3) + end + self.oldcurrent = self.current + markerdirty = false + end + + if pagedirty then + fb:refresh(0, 0, ypos, fb.bb:getWidth(), height) + pagedirty = false + end + + local ev = input.waitForEvent() + if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then + if ev.code == KEY_FW_UP then + prevItem() + elseif ev.code == KEY_FW_DOWN then + nextItem() + elseif ev.code == KEY_PGFWD then + if self.page < (self.items / perpage) then + if self.current + self.page*perpage > self.items then + self.current = self.items - self.page*perpage + end + self.page = self.page + 1 + pagedirty = true + else + self.current = self.items - (self.page-1)*perpage + markerdirty = true + end + elseif ev.code == KEY_PGBCK then + if self.page > 1 then + self.page = self.page - 1 + pagedirty = true + else + self.current = 1 + markerdirty = true + end + elseif ev.code == KEY_S then + old_keywords = keywords + keywords = InputBox:input(height-100, 100, "Search:", old_keywords) + if keywords then + self:setSearchResult(keywords) + else + keywords = old_keywords + end + pagedirty = true + elseif ev.code == KEY_ENTER or ev.code == KEY_FW_PRESS then + -- return full file path + file_entry = self.files[perpage*(self.page-1)+self.current] + return file_entry.dir .. "/" .. file_entry.name + elseif ev.code == KEY_BACK then + return nil + end + end + end +end diff --git a/inputbox.lua b/inputbox.lua new file mode 100644 index 000000000..2c50d6882 --- /dev/null +++ b/inputbox.lua @@ -0,0 +1,172 @@ +require "rendertext" +require "keys" +require "graphics" + +InputBox = { + -- Class vars: + input_start_x = 145, + input_start_y = nil, + input_cur_x = nil, -- points to the start of next input pos + + input_bg = 1, + + input_string = "", + + -- font for displaying input content + face = freetype.newBuiltinFace("mono", 25), + fhash = "m25", + fheight = 25, + fwidth = 16, +} + +function InputBox:setDefaultInput(text) + self.input_string = "" + self:addString(text) + --renderUtf8Text(fb.bb, self.input_start_x, self.input_start_y, + --self.face, self.fhash, text, true) + --self.input_cur_x = self.input_start_x + (string.len(text) * self.fwidth) + --self.input_string = text +end + +function InputBox:addString(str) + for i = 1, #str do + self:addChar(str:sub(i,i)) + end +end + +function InputBox:addChar(char) + renderUtf8Text(fb.bb, self.input_cur_x, self.input_start_y, self.face, self.fhash, + char, true) + fb:refresh(1, self.input_cur_x, self.input_start_y-19, self.fwidth, self.fheight) + self.input_cur_x = self.input_cur_x + self.fwidth + self.input_string = self.input_string .. char +end + +function InputBox:delChar() + if self.input_start_x == self.input_cur_x then + return + end + self.input_cur_x = self.input_cur_x - self.fwidth + --fill last character with blank rectangle + fb.bb:paintRect(self.input_cur_x, self.input_start_y-19, + self.fwidth, self.fheight, self.input_bg) + fb:refresh(1, self.input_cur_x, self.input_start_y-19, self.fwidth, self.fheight) + self.input_string = self.input_string:sub(0,-2) +end + +function InputBox:drawBox(ypos, w, h, title) + -- draw input border + fb.bb:paintRect(20, ypos, w, h, 5) + -- draw input slot + fb.bb:paintRect(140, ypos + 10, w - 130, h - 20, self.input_bg) + -- draw input title + renderUtf8Text(fb.bb, 35, self.input_start_y, self.face, self.fhash, + title, true) +end + + +--[[ + || d_text default to nil (used to set default text in input slot) +--]] +function InputBox:input(ypos, height, title, d_text) + local pagedirty = true + -- do some initilization + self.input_start_y = ypos + 35 + self.input_cur_x = self.input_start_x + + if d_text then -- if specified default text, draw it + w = fb.bb:getWidth() - 40 + h = height - 45 + self:drawBox(ypos, w, h, title) + self:setDefaultInput(d_text) + fb:refresh(1, 20, ypos, w, h) + pagedirty = false + else -- otherwise, leave the draw task to the main loop + self.input_string = "" + end + + while true do + if pagedirty then + w = fb.bb:getWidth() - 40 + h = height - 45 + self:drawBox(ypos, w, h, title) + fb:refresh(1, 20, ypos, w, h) + pagedirty = false + end + + local ev = input.waitForEvent() + if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then + print("key code:"..ev.code) + --ev.code = adjustFWKey(ev.code) + if ev.code == KEY_FW_UP then + elseif ev.code == KEY_FW_DOWN then + elseif ev.code == KEY_A then + self:addChar("a") + elseif ev.code == KEY_B then + self:addChar("b") + elseif ev.code == KEY_C then + self:addChar("c") + elseif ev.code == KEY_D then + self:addChar("d") + elseif ev.code == KEY_E then + self:addChar("e") + elseif ev.code == KEY_F then + self:addChar("f") + elseif ev.code == KEY_G then + self:addChar("g") + elseif ev.code == KEY_H then + self:addChar("h") + elseif ev.code == KEY_I then + self:addChar("i") + elseif ev.code == KEY_J then + self:addChar("j") + elseif ev.code == KEY_K then + self:addChar("k") + elseif ev.code == KEY_L then + self:addChar("l") + elseif ev.code == KEY_M then + self:addChar("m") + elseif ev.code == KEY_N then + self:addChar("n") + elseif ev.code == KEY_O then + self:addChar("o") + elseif ev.code == KEY_P then + self:addChar("p") + elseif ev.code == KEY_Q then + self:addChar("q") + elseif ev.code == KEY_R then + self:addChar("r") + elseif ev.code == KEY_S then + self:addChar("s") + elseif ev.code == KEY_T then + self:addChar("t") + elseif ev.code == KEY_U then + self:addChar("u") + elseif ev.code == KEY_V then + self:addChar("v") + elseif ev.code == KEY_W then + self:addChar("w") + elseif ev.code == KEY_X then + self:addChar("x") + elseif ev.code == KEY_Y then + self:addChar("y") + elseif ev.code == KEY_Z then + self:addChar("z") + elseif ev.code == KEY_SPACE then + self:addChar(" ") + elseif ev.code == KEY_PGFWD then + elseif ev.code == KEY_PGBCK then + elseif ev.code == KEY_ENTER or ev.code == KEY_FW_PRESS then + if self.input_string == "" then + return nil + else + return self.input_string + end + elseif ev.code == KEY_DEL then + self:delChar() + elseif ev.code == KEY_BACK then + return nil + end + end + end +end diff --git a/keys.lua b/keys.lua index b757dd5b0..eb932176a 100644 --- a/keys.lua +++ b/keys.lua @@ -109,22 +109,45 @@ function set_emu_keycodes() KEY_PGFWD = 117 KEY_PGBCK = 112 KEY_BACK = 22 -- backspace + KEY_DEL = 119 -- Delete KEY_MENU = 67 -- F1 KEY_FW_UP = 111 KEY_FW_DOWN = 116 KEY_FW_LEFT = 113 KEY_FW_RIGHT = 114 KEY_FW_PRESS = 36 -- enter for now + KEY_SPACE = 65 KEY_ENTER = 36 + KEY_Q = 24 + KEY_W = 25 + KEY_E = 26 + KEY_R = 27 + KEY_T = 28 + KEY_Y = 29 + KEY_U = 30 + KEY_I = 31 + KEY_O = 32 + KEY_P = 33 + KEY_A = 38 KEY_S = 39 KEY_D = 40 KEY_F = 41 - + KEY_G = 42 + KEY_H = 43 KEY_J = 44 KEY_K = 45 + KEY_L = 46 + + KEY_Z = 52 + KEY_X = 53 + KEY_C = 54 + KEY_V = 55 + KEY_B = 56 + KEY_N = 57 + KEY_M = 58 KEY_SHIFT = 50 -- left shift KEY_ALT = 64 -- left alt