diff --git a/Makefile b/Makefile index 53b49e786..fe7e4414a 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ TTF_FONTS_DIR=$(MUPDFDIR)/fonts # set this to your ARM cross compiler: -HOST:=arm-kindle-linux-gnueabi +HOST:=arm-none-linux-gnueabi CC:=$(HOST)-gcc CXX:=$(HOST)-g++ STRIP:=$(HOST)-strip @@ -27,16 +27,14 @@ endif HOSTCC:=gcc HOSTCXX:=g++ -SYSROOT=/usr/local/arm/$(HOST)/$(HOST)/sysroot/ -CFLAGS:=-O3 --sysroot=$(SYSROOT) -CXXFLAGS:=-O3 --sysroot=$(SYSROOT) -LDFLAGS:= --sysroot=$(SYSROOT) +CFLAGS:=-O3 $(SYSROOT) +CXXFLAGS:=-O3 $(SYSROOT) +LDFLAGS:= $(SYSROOT) ARM_CFLAGS:=-march=armv6 # use this for debugging: #CFLAGS:=-O0 -g DYNAMICLIBSTDCPP:=-lstdc++ -STATICLIBSTDCPP=$(SYSROOT)lib/libstdc++.a ifdef STATICLIBSTDCPP DYNAMICLIBSTDCPP:= endif @@ -126,7 +124,7 @@ djvu.o: %.o: %.c $(CC) -c $(KPDFREADER_CFLAGS) -I$(DJVUDIR)/ $< -o $@ cre.o: %.o: %.cpp - $(CC) -c -I$(CRENGINEDIR)/crengine/include/ -I$(LUADIR)/src $< -o $@ + $(CC) -c -I$(CRENGINEDIR)/crengine/include/ -I$(LUADIR)/src $< -o $@ -lstdc++ lfs.o: $(LFSDIR)/src/lfs.c $(CC) -c $(CFLAGS) -I$(LUADIR)/src -I$(LFSDIR)/src $(LFSDIR)/src/lfs.c -o $@ @@ -202,7 +200,7 @@ $(LUALIB): ifdef EMULATE_READER make -C $(LUADIR) else - make -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CROSS="$(HOST)-" TARGET_FLAGS="--sysroot=$(SYSROOT) -DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2" + make -C $(LUADIR) CC="$(HOSTCC)" HOST_CC="$(HOSTCC) -m32" CROSS="$(HOST)-" TARGET_FLAGS="$(SYSROOT) -DLUAJIT_NO_LOG2 -DLUAJIT_NO_EXP2" endif thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) $(CRENGINELIBS) diff --git a/cre.cpp b/cre.cpp index 7a2e09503..87fec7cfc 100644 --- a/cre.cpp +++ b/cre.cpp @@ -17,6 +17,7 @@ along with this program. If not, see . */ +#define DEBUG_CRENGINE 0 extern "C" { #include "blitbuffer.h" @@ -424,6 +425,73 @@ static int registerFont(lua_State *L) { return 0; } +// ported from Android UI kpvcrlib/crengine/android/jni/docview.cpp + +static int findText(lua_State *L) { + CreDocument *doc = (CreDocument*) luaL_checkudata(L, 1, "credocument"); + const char *l_pattern = luaL_checkstring(L, 2); + lString16 pattern = lString16(l_pattern); + int origin = luaL_checkint(L, 3); + bool reverse = luaL_checkint(L, 4); + bool caseInsensitive = luaL_checkint(L, 5); + + if ( pattern.empty() ) + return 0; + + LVArray words; + lvRect rc; + doc->text_view->GetPos( rc ); + int pageHeight = rc.height(); + int start = -1; + int end = -1; + if ( reverse ) { + // reverse + if ( origin == 0 ) { + // from end current page to first page + end = rc.bottom; + } else if ( origin == -1 ) { + // from last page to end of current page + start = rc.bottom; + } else { // origin == 1 + // from prev page to first page + end = rc.top; + } + } else { + // forward + if ( origin == 0 ) { + // from current page to last page + start = rc.top; + } else if ( origin == -1 ) { + // from first page to current page + end = rc.top; + } else { // origin == 1 + // from next page to last + start = rc.bottom; + } + } + CRLog::debug("CRViewDialog::findText: Current page: %d .. %d", rc.top, rc.bottom); + CRLog::debug("CRViewDialog::findText: searching for text '%s' from %d to %d origin %d", LCSTR(pattern), start, end, origin ); + if ( doc->text_view->getDocument()->findText( pattern, caseInsensitive, reverse, start, end, words, 200, pageHeight ) ) { + CRLog::debug("CRViewDialog::findText: pattern found"); + doc->text_view->clearSelection(); + doc->text_view->selectWords( words ); + ldomMarkedRangeList * ranges = doc->text_view->getMarkedRanges(); + if ( ranges ) { + if ( ranges->length()>0 ) { + int pos = ranges->get(0)->start.y; + //doc->text_view->SetPos(pos); // commented out not to mask lua code which does the same + CRLog::debug("# SetPos = %d", pos); + lua_pushinteger(L, ranges->length()); // results found + lua_pushinteger(L, pos); + return 2; + } + } + return 0; + } + CRLog::debug("CRViewDialog::findText: pattern not found"); + return 0; +} + static const struct luaL_Reg cre_func[] = { {"openDocument", openDocument}, {"getFontFaces", getFontFaces}, @@ -459,6 +527,7 @@ static const struct luaL_Reg credocument_meth[] = { //{"cursorLeft", cursorLeft}, //{"cursorRight", cursorRight}, {"drawCurrentPage", drawCurrentPage}, + {"findText", findText}, {"close", closeDocument}, {"__gc", closeDocument}, {NULL, NULL} diff --git a/crereader.lua b/crereader.lua index 56afb136e..e4d4d9878 100644 --- a/crereader.lua +++ b/crereader.lua @@ -592,3 +592,40 @@ function CREReader:adjustCreReaderCommands() end ) end + + +---------------------------------------------------- +--- search +---------------------------------------------------- +function CREReader:searchHighLight(search) + Debug("FIXME CreReader::searchHighLight", search) + + if self.last_search == nil or self.last_search.search == nil then + self.last_search = { + search = "", + } + end + + local origin = 0 -- 0=current 1=next-last -1=first-current + if self.last_search.search == search then + origin = 1 + end + + local found, pos = self.doc:findText( + search, + origin, + 0, -- reverse: boolean + 1 -- caseInsensitive: boolean + ) + + if found then + self.pos = pos -- first metch position + self:redrawCurrentPage() + showInfoMsgWithDelay( found.." hits '"..search.."' pos "..pos, 2000, 1) + else + showInfoMsgWithDelay( "'"..search.."' not found in document", 2000, 1) + end + + self.last_search.search = search + +end diff --git a/filechooser.lua b/filechooser.lua index 42556d6ff..bea01335b 100644 --- a/filechooser.lua +++ b/filechooser.lua @@ -402,9 +402,12 @@ function FileChooser:addAllCommands() function(self) local oldname = self:FullFileName() if oldname then - local newname = InputBox:input(0, 0, "New filename:", "including extension", true) + local name_we = self.files[self.perpage*(self.page-1)+self.current - #self.dirs] + local ext = string.lower(string.match(oldname, ".+%.([^.]+)") or "") + name_we = string.sub(name_we,1,-2-string.len(ext)) + local newname = InputBox:input(0, 0, "New filename:", name_we) if newname then - newname = self.path.."/"..newname + newname = self.path.."/"..newname..'.'..ext os.rename(oldname, newname) os.rename(DocToHistory(oldname), DocToHistory(newname)) self:setPath(self.path) @@ -546,6 +549,14 @@ function FileChooser:addAllCommands() return "break" end ) + self.commands:add(KEY_K, MOD_SHIFT, "K", + "run calculator", + function(self) + local CalcBox = InputBox:new{ calcmode = true } + CalcBox:input(0, 0, "Calc ") + self.pagedirty = true + end + ) end -- NuPogodi, 23.05.12: returns full filename or nil (if folder) diff --git a/helppage.lua b/helppage.lua index e9d5cad2c..869608dce 100644 --- a/helppage.lua +++ b/helppage.lua @@ -40,8 +40,8 @@ HelpPage = { -- Other Class vars: - -function HelpPage:show(ypos, height, commands) +-- 02.06.12: added parameter 'title' for the header to make this function usable for various documentation purposes +function HelpPage:show(ypos, height, commands, title) self.commands = {} self.items = 0 local keys = {} @@ -66,7 +66,8 @@ function HelpPage:show(ypos, height, commands) fface_height = math.ceil(fface_height) fface_ascender = math.ceil(fface_ascender) local spacing = face_height + 5 - local vert_S = self.title_H + 12 + -- 02.06.12: minor correction to vertical position of displayed items + local vert_S = self.title_H + 3 local perpage = math.floor( (height - ypos - 1 * (fface_height + 5) - vert_S) / spacing ) self.page = 1 @@ -75,8 +76,8 @@ function HelpPage:show(ypos, height, commands) while true do if is_pagedirty then fb.bb:paintRect(0, ypos, fb.bb:getWidth(), height, 0) - -- draw header - DrawTitle("Active Hotkeys",self.margin_H,0,self.title_H,self.bg_color,Font:getFace("tfont", 25)) + -- 02.06.12: one should use it here + DrawTitle(title or "Active Hotkeys",self.margin_H,0,self.title_H,self.bg_color,Font:getFace("tfont", 25)) local c local max_x = 0 for c = 1, perpage do diff --git a/inputbox.lua b/inputbox.lua index 923194854..10e0c2467 100644 --- a/inputbox.lua +++ b/inputbox.lua @@ -6,7 +6,6 @@ require "graphics" ---------------------------------------------------- -- General inputbox ---------------------------------------------------- - InputBox = { -- Class vars: h = 100, @@ -25,9 +24,7 @@ InputBox = { fheight = 25, fwidth = 15, commands = nil, - initialized = false, - - -- NuPogodi, 25.05.12: for full UTF8 support + vk_bg = 3, charlist = {}, -- table to store input string charpos = 1, @@ -35,12 +32,13 @@ InputBox = { -- values to control layouts: min & max min_layout = 2, max_layout = 9, - -- default layout = 2, i.e. shiftmode = symbolmode = utf8mode = false - layout = 2, + layout = 3, -- now bits to toggle the layout mode - shiftmode = true, -- toggle chars <> capitals, lowest bit in (layout-2) - symbolmode = false, -- toggle chars <> symbols, middle bit in (layout-2) - utf8mode = false, -- toggle english <> national, highest bit in (layout-2) + shiftmode = true, -- toggle chars <-> capitals, lowest bit in (layout-2) + symbolmode = false, -- toggle chars <-> symbols, middle bit in (layout-2) + utf8mode = false, -- toggle english <-> national, highest bit in (layout-2) + calcmode = false, -- toggle calculator mode + calcfunctions = nil, -- math functions for calculator helppage } function InputBox:new(o) @@ -127,8 +125,13 @@ end ---------------------------------------------------------------------- function InputBox:input(ypos, height, title, d_text, is_hint) -- To avoid confusion with old ypos & height parameters, I'd better define - -- my own position, at the bottom screen edge (NuPogodi, 26.05.12) + -- my own position, at the bottom screen edge ypos = fb.bb:getHeight() - 165 + -- some corrections for calculator mode + if self.calcmode then + self:setCalcMode() + end + -- at first, draw titled box and content local h, w = 55, fb.bb:getWidth() - 2 self:drawBox(ypos, w, h, title) @@ -142,21 +145,16 @@ function InputBox:input(ypos, height, title, d_text, is_hint) y_pos = ypos + 13, h = 30, } + if d_text then if is_hint then - -- print hint text + -- print hint text fb.bb:paintRect(self.input_start_x-5, self.input_start_y-19, self.input_slot_w, self.fheight, self.input_bg) renderUtf8Text(fb.bb, self.input_start_x+5, self.input_start_y, self.face, d_text, 0) fb.bb:dimRect(self.input_start_x-5, self.input_start_y-19, self.input_slot_w, self.fheight, self.input_bg) else - self.input_string = d_text - string.gsub( d_text, "(.)", function(char) - table.insert(self.charlist, self.charpos, char) - self.charpos = self.charpos + 1 - return "" - end) - Debug("charlist", self.charlist) - + -- add text to input_string + self:StringToCharlist(d_text) self.input_cur_x = self.input_cur_x + (self.fwidth * #self.charlist) self.cursor.x_pos = self.cursor.x_pos + (self.fwidth * #self.charlist) self:refreshText() @@ -164,8 +162,10 @@ function InputBox:input(ypos, height, title, d_text, is_hint) end self.cursor:draw() fb:refresh(1, 1, ypos, w, h) + + local ev, keydef, command, ret_code while true do - local ev = input.saveWaitForEvent() + ev = input.saveWaitForEvent() ev.code = adjustKeyEvents(ev) if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then keydef = Keydef:new(ev.code, getKeyModifier()) @@ -183,62 +183,63 @@ function InputBox:input(ypos, height, title, d_text, is_hint) end end -- if end -- while - local return_str = self.input_string + + local output = self.input_string self.input_string = "" self.charlist = {} self.charpos = 1 - return return_str + return output end function InputBox:setLayoutsTable() - -- trying to read the layout from the user-defined file "mykeyboard.lua" - local ok, stored = pcall(dofile,"./mykeyboard.lua") + -- trying to read the layout from the user-defined file + local ok, stored = pcall(dofile, lfs.currentdir() .. "/mykeyboard.lua") if ok then self.INPUT_KEYS = stored else -- if an error happens, we use the default layout self.INPUT_KEYS = { { KEY_Q, "Q", "q", "1", "!", "Я", "я", "1", "!", }, { KEY_W, "W", "w", "2", "?", "Ж", "ж", "2", "?", }, - { KEY_E, "E", "e", "3", "#", "Е", "е", "3", "«", }, - { KEY_R, "R", "r", "4", "@", "Р", "р", "4", "»", }, - { KEY_T, "T", "t", "5", "%", "Т", "т", "5", ":", }, + { KEY_E, "E", "e", "3", "|", "Е", "е", "3", "«", }, + { KEY_R, "R", "r", "4", "#", "Р", "р", "4", "»", }, + { KEY_T, "T", "t", "5", "@", "Т", "т", "5", ":", }, { KEY_Y, "Y", "y", "6", "‰", "Ы", "ы", "6", ";", }, - { KEY_U, "U", "u", "7", "\'", "У", "у", "7", "~", }, + { KEY_U, "U", "u", "7", "'", "У", "у", "7", "~", }, { KEY_I, "I", "i", "8", "`", "И", "и", "8", "(",}, { KEY_O, "O", "o", "9", ":", "О", "о", "9", ")",}, { KEY_P, "P", "p", "0", ";", "П", "п", "0", "=", }, -- middle raw { KEY_A, "A", "a", "+", "…", "А", "а", "Ш", "ш", }, { KEY_S, "S", "s", "-", "_", "С", "с", "Ѕ", "ѕ", }, - { KEY_D, "D", "d", "*", "¦", "Д", "д", "Э", "э", }, - { KEY_F, "F", "f", "/", "|", "Ф", "ф", "Ю", "ю", }, - { KEY_G, "G", "g", "\\", "„", "Г", "г", "Ґ", "ґ", }, - { KEY_H, "H", "h", "=", "“", "Ч", "ч", "Ј", "ј", }, + { KEY_D, "D", "d", "*", "=", "Д", "д", "Э", "э", }, + { KEY_F, "F", "f", "/", "\\", "Ф", "ф", "Ю", "ю", }, + { KEY_G, "G", "g", "%", "„", "Г", "г", "Ґ", "ґ", }, + { KEY_H, "H", "h", "^", "“", "Ч", "ч", "Ј", "ј", }, { KEY_J, "J", "j", "<", "”", "Й", "й", "І", "і", }, - { KEY_K, "K", "k", "ˆ", "\"", "К", "к", "Ќ", "ќ", }, + { KEY_K, "K", "k", "=", "\"", "К", "к", "Ќ", "ќ", }, { KEY_L, "L", "l", ">", "~", "Л", "л", "Љ", "љ", }, -- lowest raw { KEY_Z, "Z", "z", "(", "$", "З", "з", "Щ", "щ", }, { KEY_X, "X", "x", ")", "€", "Х", "х", "№", "@", }, - { KEY_C, "C", "c", "{", "¥", "Ц", "ц", "Џ", "џ", }, - { KEY_V, "V", "v", "}", "£", "В", "в", "Ў", "ў", }, - { KEY_B, "B", "b", "[", "‚", "Б", "б", "Ћ", "ћ", }, - { KEY_N, "N", "n", "]", "‘", "Н", "н", "Њ", "њ", }, - { KEY_M, "M", "m", "&", "’", "М", "м", "Ї", "ї", }, - { KEY_DOT, ".", ",", ".", ",", ".", ",", "Є", "є", }, + { KEY_C, "C", "c", "&", "¥", "Ц", "ц", "Џ", "џ", }, + { KEY_V, "V", "v", ":", "£", "В", "в", "Ў", "ў", }, + { KEY_B, "B", "b", "π", "‚", "Б", "б", "Ћ", "ћ", }, + { KEY_N, "N", "n", "е", "‘", "Н", "н", "Њ", "њ", }, + { KEY_M, "M", "m", "~", "’", "М", "м", "Ї", "ї", }, + { KEY_DOT, ",", ".", ".", ",", ",", ".", "Є", "є", }, -- Let us make key 'Space' the same for all layouts { KEY_SPACE," ", " ", " ", " ", " ", " ", " ", " ", }, - -- Simultaneous pressing Alt + Q..P should also work properly - { KEY_1, "1", " ", " ", " ", "1", " ", " ", " ", }, - { KEY_2, "2", " ", " ", " ", "2", " ", " ", " ", }, - { KEY_3, "3", " ", " ", " ", "3", " ", " ", " ", }, - { KEY_4, "4", " ", " ", " ", "4", " ", " ", " ", }, - { KEY_5, "5", " ", " ", " ", "5", " ", " ", " ", }, - { KEY_6, "6", " ", " ", " ", "6", " ", " ", " ", }, - { KEY_7, "7", " ", " ", " ", "7", " ", " ", " ", }, - { KEY_8, "8", " ", " ", " ", "8", " ", " ", " ", }, - { KEY_9, "9", " ", " ", " ", "9", " ", " ", " ", }, - { KEY_0, "0", " ", " ", " ", "0", " ", " ", " ", }, + -- Simultaneous pressing Alt + Q..P should also work properly everywhere + { KEY_1, "1", "1", "1", "1", "1", "1", "1", "1", }, + { KEY_2, "2", "2", "2", "2", "2", "2", "2", "2", }, + { KEY_3, "3", "3", "3", "3", "3", "3", "3", "3", }, + { KEY_4, "4", "4", "4", "4", "4", "4", "4", "4", }, + { KEY_5, "5", "5", "5", "5", "5", "5", "5", "5", }, + { KEY_6, "6", "6", "6", "6", "6", "6", "6", "6", }, + { KEY_7, "7", "7", "7", "7", "7", "7", "7", "7", }, + { KEY_8, "8", "8", "8", "8", "8", "8", "8", "8", }, + { KEY_9, "9", "9", "9", "9", "9", "9", "9", "9", }, + { KEY_0, "0", "0", "0", "0", "0", "0", "0", "0", }, -- DXG keys { KEY_SLASH,"/", "\\", "/", "\\", "/", "\\", "/", "\\", }, } @@ -281,13 +282,13 @@ function InputBox:DrawVirtualKeyboard() blitbuffer.paintBorder(fb.bb, lx+9*dx-10, vy-dy-r-8, r, r, t, c, r) renderUtf8Text(fb.bb, lx-5+9*dx, vy-dy-3, smfont, "Del", true) -- Sym - blitbuffer.paintBorder(fb.bb, lx+8*dx-10, vy-r-8, r, r, t + (r-t)*number(self.symbolmode), c, r) + blitbuffer.paintBorder(fb.bb, lx+8*dx-10, vy-r-8, r, r, t + (r-t)*self:num(self.symbolmode), c, r) renderUtf8Text(fb.bb, lx-5+8*dx, vy-3, smfont, "Sym", true) -- Enter blitbuffer.paintBorder(fb.bb, lx+9*dx-10, vy-r-8, r, r, t, c, r) renderUtf8Text(fb.bb, lx+9*dx, vy-2, vkfont, "«", true) -- Menu - blitbuffer.paintBorder(fb.bb, lx+10*dx-8, vy-2*dy-r-8, r+50, r, t+(r-t)*number(self.utf8mode), c, r) + blitbuffer.paintBorder(fb.bb, lx+10*dx-8, vy-2*dy-r-8, r+50, r, t+(r-t)*self:num(self.utf8mode), c, r) renderUtf8Text(fb.bb, lx+10*dx+11, vy-2*dy-3, smfont, "Menu", true) -- fiveway local h=dy+2*r-2 @@ -296,6 +297,14 @@ function InputBox:DrawVirtualKeyboard() fb:refresh(1, 1, fb.bb:getHeight()-120, fb.bb:getWidth()-2, 120) end +function InputBox:num(bool) + return bool and 1 or 0 +end + +function InputBox:VKLayout(b1, b2, b3) + return 2 + self:num(b1) + 2 * self:num(b2) + 4 * self:num(b3) +end + function InputBox:addCharCommands(layout) -- at first, let's define self.layout and extract separate bits as layout modes if layout then @@ -306,25 +315,48 @@ function InputBox:addCharCommands(layout) -- fill the layout modes layout = (layout - 2) % 4 self.shiftmode = (layout == 1 or layout == 3) - self.symbolmode = (layout == 2 or layout == 3) + self.symbolmode = (layout == 2 or layout == 4) self.utf8mode = (self.layout > 5) else -- or, without input parameter, restore layout from current layout modes - self.layout = 2 + number(self.shiftmode) + 2 * number(self.symbolmode) + 4 * number(self.utf8mode) + self.layout = self:VKLayout(self.shiftmode, self.symbolmode, self.utf8mode) end + -- let's define layout called by Shift+Key (to type capitalized chars being in low-case layout) + local shift_layout = self:VKLayout(not self.shiftmode, self.symbolmode, self.utf8mode) -- adding the commands for k,v in ipairs(self.INPUT_KEYS) do - -- seems to work without removing old commands, - self.commands:del(v[1], nil, "") - -- just redefining existing ones - self.commands:add(v[1], nil, "", "input "..v[self.layout], + -- just redefining existing + self.commands:add(v[1], nil, "A..Z", "enter character from virtual keyboard (VK)", function(self) self:addChar(v[self.layout]) end ) + -- and commands for chars pressed with Shift + self.commands:add(v[1], MOD_SHIFT, "A..Z", "enter capitalized VK-character", + function(self) + self:addChar(v[shift_layout]) + end + ) end self:DrawVirtualKeyboard() end +function InputBox:StringToCharlist(text) + if text == nill then return end + -- clear + self.charlist = {} + self.charpos = 1 + local prevcharcode, charcode = 0 + for uchar in string.gfind(text, "([%z\1-\127\194-\244][\128-\191]*)") do + charcode = util.utf8charcode(uchar) + if prevcharcode then -- utf8 + self.charlist[#self.charlist+1] = uchar + end + prevcharcode = charcode + end + self.input_string = self:CharlistToString() + self.charpos = #self.charlist+1 +end + function InputBox:CharlistToString() local s, i = "" for i=1, #self.charlist do @@ -333,22 +365,25 @@ function InputBox:CharlistToString() return s end -function number(bool) - return bool and 1 or 0 -end - function InputBox:addAllCommands() - -- we only initialize once + -- if already initialized, we (re)define only calcmode-dependent commands if self.commands then + self:ModeDependentCommands() self:DrawVirtualKeyboard() return end self:setLayoutsTable() self.commands = Commands:new{} - -- adding command to enter character commands - self:addCharCommands() + -- adding character commands + self:addCharCommands(self.layout) -- adding the rest commands (independent of the selected layout) - self.commands:add(KEY_FW_LEFT, nil, "", + self.commands:add(KEY_H, MOD_ALT, "H", + "show helppage", + function(self) + self:showHelpPage(self.commands) + end + ) + self.commands:add(KEY_FW_LEFT, nil, "joypad left", "move cursor left", function(self) if (self.cursor.x_pos + 3) > self.input_start_x then @@ -358,7 +393,17 @@ function InputBox:addAllCommands() end end ) - self.commands:add(KEY_FW_RIGHT, nil, "", + self.commands:add(KEY_FW_LEFT, MOD_SHIFT, "left", + "move cursor to the first position", + function(self) + if (self.cursor.x_pos + 3) > self.input_start_x then + self.cursor:moveHorizontalAndDraw(-self.fwidth*(self.charpos-1)) + self.charpos = 1 + fb:refresh(1, self.input_start_x-5, self.ypos, self.input_slot_w, self.h) + end + end + ) + self.commands:add(KEY_FW_RIGHT, nil, "joypad right", "move cursor right", function(self) if (self.cursor.x_pos + 3) < self.input_cur_x then @@ -368,75 +413,235 @@ function InputBox:addAllCommands() end end ) - self.commands:add({KEY_ENTER, KEY_FW_PRESS}, nil, "", - "submit input content", + self.commands:add(KEY_FW_RIGHT, MOD_SHIFT, "right", + "move cursor to the last position", function(self) - if self.input_string == "" then - self.input_string = nil + if (self.cursor.x_pos + 3) < self.input_cur_x then + self.cursor:moveHorizontalAndDraw(self.fwidth*(#self.charlist+1-self.charpos)) + self.charpos = #self.charlist + 1 + fb:refresh(1, self.input_start_x-5, self.ypos, self.input_slot_w, self.h) end - return "break" end ) - self.commands:add(KEY_DEL, nil, "", + self.commands:add(KEY_DEL, nil, "Del", "delete one character", function(self) self:delChar() end ) - self.commands:add(KEY_DEL, MOD_SHIFT, "", - "empty inputbox", + self.commands:add(KEY_DEL, MOD_SHIFT, "Del", + "delete all characters (empty inputbox)", function(self) self:clearText() end ) - self.commands:add({KEY_BACK, KEY_HOME}, nil, "", - "cancel inputbox", + self.commands:addGroup("up/down", { Keydef:new(KEY_FW_DOWN, nil), Keydef:new(KEY_FW_UP, nil) }, + "goto previous/next VK-layout", function(self) - self.input_string = nil - return "break" - end - ) - self.commands:add(KEY_P, MOD_SHIFT, "P", - "make screenshot", - function(self) - Screen:screenshot() - end - ) - self.commands:add(KEY_FW_DOWN, nil, "joypad down", - "goto next keyboard layout", - function(self) - if self.layout == self.max_layout then self:addCharCommands(self.min_layout) - else self:addCharCommands(self.layout+1) end - end - ) - self.commands:add(KEY_FW_UP, nil, "joypad up", - "goto previous keyboard layout", - function(self) - if self.layout == self.min_layout then self:addCharCommands(self.max_layout) - else self:addCharCommands(self.layout-1) end + if keydef.keycode == KEY_FW_DOWN then + if self.layout == self.max_layout then self:addCharCommands(self.min_layout) + else self:addCharCommands(self.layout+1) end + else -- KEY_FW_UP + if self.layout == self.min_layout then self:addCharCommands(self.max_layout) + else self:addCharCommands(self.layout-1) end + end + end ) self.commands:add(KEY_AA, nil, "Aa", - "toggle layout: chars <> CHARS", + "toggle VK-layout: chars <> CHARS", function(self) self.shiftmode = not self.shiftmode self:addCharCommands() end ) self.commands:add(KEY_SYM, nil, "Sym", - "toggle layout: chars <> symbols", + "toggle VK-layout: chars <> symbols", function(self) self.symbolmode = not self.symbolmode self:addCharCommands() end ) self.commands:add(KEY_MENU, nil, "Menu", - "toggle layout: english <> national", + "toggle VK-layout: english <> national", function(self) self.utf8mode = not self.utf8mode self:addCharCommands() end ) + -- NuPogodi, 02.06.12: calcmode-dependent commands are collected + self:ModeDependentCommands() -- here + + self.commands:add({KEY_BACK, KEY_HOME}, nil, "Back", + "back", + function(self) + self.input_string = nil + return "break" + end + ) +end +----------------------------------------------------------------- +-- NuPogodi, 02.06.12: Some Help- & Calculator-related functions +----------------------------------------------------------------- +function InputBox:defineCalcFunctions() -- for the calculator documentation + -- to initialize only once + if self.calcfunctions then return end + + self.calcfunctions = Commands:new{} + -- remove initially added commands + self.calcfunctions:del(KEY_INTO_SCREEN_SAVER, nil, "Slider") + self.calcfunctions:del(KEY_OUTOF_SCREEN_SAVER, nil, "Slider") + self.calcfunctions:del(KEY_CHARGING, nil, "plugin/out usb") + self.calcfunctions:del(KEY_NOT_CHARGING, nil, "plugin/out usb") + self.calcfunctions:del(KEY_SPACE, MOD_ALT, "Space") + + local s = " " -- space for function groups + local a = 100 -- arithmetic functions + self.calcfunctions:add(a-1, nil, s:rep(1), string.upper("Ariphmetic operators")) + self.calcfunctions:add(a, nil, "+ -", "addition: 1+2=3; substraction: 3-2=1") + self.calcfunctions:add(a+1, nil, "* /", "multiplication: 2*2=4; division: 4/2=2") + self.calcfunctions:add(a+3, nil, "%", "modulo (remainder): 5.2%2=1.2, π-π%0.01=3.14") + local r = 200 -- relations + self.calcfunctions:add(r-1, nil, s:rep(2), string.upper("Relational operators")) + self.calcfunctions:add(r, nil, "< >", "less: (2<3)=true; more: (2>3)=false") + self.calcfunctions:add(r+1, nil, "<=", "less or equal: (3≤3)=true, (2≤1)=false") + self.calcfunctions:add(r+2, nil, ">=", "more or equal: (3≥3)=true, (1≥2)=false") + self.calcfunctions:add(r+3, nil, "==", "equal: (3==3)=true, (1==2)=false") + self.calcfunctions:add(r+4, nil, "~=", "not equal: (6~=8)=true, (3~=3)=false") + local l = 300 -- logical + self.calcfunctions:add(l-1, nil, s:rep(3), string.upper("Logical operators")) + self.calcfunctions:add(l+0, nil, "and, &", "= logical 'and': (4 and 5)=5, (nil & 5)=nil") + self.calcfunctions:add(l+1, nil, "or, |", "= logical 'or': (4 or 5)=4, (false | 5)=5") + local c = 400 -- constants + self.calcfunctions:add(c-1, nil, s:rep(4), string.upper("Some constants")) + self.calcfunctions:add(c, nil, "pi, π", "= 3.14159…; sin(π/2)=1, cos(π/2)=0") + self.calcfunctions:add(c+1, nil, "е, exp(1)", "= 2.71828…; log(е)=1") + local m = 500 -- mathematical + self.calcfunctions:add(m-1, nil, s:rep(5), string.upper("Mathematic functions")) + self.calcfunctions:add(m, nil, "abs(x)", "absolute value of x: abs(1)=1, abs(-2)=2") + self.calcfunctions:add(m+1, nil, "ceil(x)", "round to integer no less than x: ceil(0.4)=1") + self.calcfunctions:add(m+2, nil, "floor(x)", "round to integer no greater than x: floor(0.4)=0") + self.calcfunctions:add(m+3, nil, "^, pow(x,y)","= power: 2^10=1024, pow(4,0.5)=2") + self.calcfunctions:add(m+4, nil, "exp(x), e^x","= exponent: exp(1)=2.71828…") + self.calcfunctions:add(m+5, nil, "log(x)", "the natural logarithm: log(e)=1") + self.calcfunctions:add(m+6, nil, "log10(x)", "the base 10 logarithm: log10(10)=1") + self.calcfunctions:add(m+7, nil, "max(x,…)", "return maximal value: max(0,-1,2,1)=2") + self.calcfunctions:add(m+8, nil, "min(x,…)", "return minimal value: min(0,-1,2,1)=-1") + self.calcfunctions:add(m+9, nil, "sqrt(x)", "return square root: sqrt(4)=2") + local t = 600 -- trigonometrical + self.calcfunctions:add(t, nil, s:rep(6), string.upper("Trigonometric functions")) + self.calcfunctions:add(t+1, nil, "deg(x)", "convert radians to degrees: deg(π/2)=90") + self.calcfunctions:add(t+2, nil, "rad(x)", "convert degrees to radians: rad(180)=3.14159…") + self.calcfunctions:add(t+3, nil, "sin(x)", "sine for x given in radians: sin(π/2)=1") + self.calcfunctions:add(t+4, nil, "cos(x)", "cosine for x given in radians: cos(π)=-1") + self.calcfunctions:add(t+5, nil, "tan(x)", "tangent for x given in radians: tan(π/4)=1") + self.calcfunctions:add(t+6, nil, "asin(x)", "inverse sine (in radians): asin(1)/π=0.5") + self.calcfunctions:add(t+7, nil, "acos(x)", "inverse cosine (in radians): acos(0)/π=0.5") + self.calcfunctions:add(t+8, nil, "atan(x)", "inverse tangent (in radians): atan(1)/π=0.25") + self.calcfunctions:add(t+9, nil, "atan2(x,y)", "inverse tangent of two args: = atan(x/y)") + local h = 700 -- hyperbolical + self.calcfunctions:add(h, nil, s:rep(7), string.upper("Hyperbolic functions")) + self.calcfunctions:add(h+1, nil, "sinh(x)", "hyperbolic sine, (exp(x)-exp(-x))/2") + self.calcfunctions:add(h+2, nil, "cosh(x)", "hyperbolic cosine, (exp(x)+exp(-x))/2") + self.calcfunctions:add(h+3, nil, "tanh(x)", "hyperbolic tangent, sinh(x)/cosh(x)") +-- not yet documented > "fmod", "frexp", "huge", "ldexp", "modf", "randomseed", "random" +end + +function InputBox:showHelpPage(list, title) + -- make inactive input slot + self.cursor:clear() -- hide cursor + fb.bb:dimRect(self.input_start_x-5, self.input_start_y-19, self.input_slot_w, self.fheight, self.input_bg) + fb:refresh(1, self.input_start_x-5, self.ypos, self.input_slot_w, self.h) + -- now start the helppage with own list of commands and own title + HelpPage:show(0, fb.bb:getHeight()-165, list, title) + -- on the helppage-exit, making inactive helpage + fb.bb:dimRect(0, 40, fb.bb:getWidth(), fb.bb:getHeight()-205, self.input_bg) + fb:refresh(1, 0, 40, fb.bb:getWidth(), fb.bb:getHeight()-205) + -- and active input slot + self:refreshText() + self.cursor:draw() -- show cursor = ready to input + fb:refresh(1, self.input_start_x-5, self.ypos, self.input_slot_w, self.h) +end + +function InputBox:setCalcMode() + --clear previous input + self.input_string = "" + self.charlist = {} + self.charpos = 1 + -- set proper layouts + self.layout = 4 -- digits + self.min_layout = 3 + self.max_layout = 4 +end + +function InputBox:PrepareStringToCalc() + local s = string.lower(self.input_string) + -- continue interpreting the input + local mathe = { "abs", "acos", "asin", "atan2", "atan", "ceil", "cosh", "cos", + "deg", "exp", "floor", "fmod", "frexp", "huge", "ldexp", "log10", "log", + "max", "min", "modf", "pi", "pow", "rad", "randomseed", "random", + "sinh", "sin", "sqrt", "tanh", "tan", } + -- to avoid any ambiguities (like sin & sinh), one has to replace by capitals + for i=1, #mathe do + s = string.gsub(s, mathe[i], string.upper("math."..mathe[i])) + end + -- some acronyms for constants & functions + s = string.gsub(s, "π", " math.pi ") + s = string.gsub(s, "е", " math.exp(1) ") + s = string.gsub(s, "&", " and ") + s = string.gsub(s, "|", " or ") + -- return the whole string in lowercase and eventually replace double "math." + return string.gsub(string.lower(s), "math.math.", "math.") +end + +-- define whether we need to calculate the result or to return 'self.input_string' +function InputBox:ModeDependentCommands() + if self.calcmode then + -- define what to do with the input_string + self.commands:add({KEY_FW_PRESS, KEY_ENTER}, nil, "joypad center", + "calculate the result", + function(self) + local s = self:PrepareStringToCalc() + if pcall(function () f = assert(loadstring("r = tostring("..s..")")) end) then + f() + self:clearText() + self.cursor:clear() + for i=1, string.len(r) do + table.insert(self.charlist, string.sub(r,i,i)) + end + self.charpos = #self.charlist + 1 + self.input_string = r + self:refreshText() + self.cursor:moveHorizontal(#self.charlist*self.fwidth) + self.cursor:draw() + fb:refresh(1, self.input_start_x-5, self.input_start_y-25, self.input_slot_w, self.h-25) + else + showInfoMsgWithDelay("Wrong Input! ", 2000, 1) + end -- if pcall + end -- function + ) + -- add the calculator help (short list of available functions) + -- or, might be better, to make some help document and open it in reader ?? + self.commands:add(KEY_M, MOD_ALT, "M", + "math functions available in calculator", + function(self) + self:defineCalcFunctions() + self:showHelpPage(self.calcfunctions, "Math Functions for Calculator") + end + ) + else -- return input_string & close input box + self.commands:add({KEY_FW_PRESS, KEY_ENTER}, nil, "joypad center", + "submit input content", + function(self) + if self.input_string == "" then + self.input_string = nil + end + return "break" + end + ) + -- delete calculator-specific help + self.commands:del(KEY_M, MOD_ALT, "M") + end -- if self.calcmode end ---------------------------------------------------- @@ -445,7 +650,6 @@ end ---------------------------------------------------- NumInputBox = InputBox:new{ - symbolmode = true, layout = 4, - charlist = {} + charlist = {}, } diff --git a/unireader.lua b/unireader.lua index cd1e953fd..1d5e713c6 100644 --- a/unireader.lua +++ b/unireader.lua @@ -2563,8 +2563,10 @@ function UniReader:addAllCommands() self.commands:add(KEY_DOT, nil, ".", "search and highlight text", function(unireader) + Screen:saveCurrentBB() local search = InputBox:input(G_height - 100, 100, "Search:", self.last_search.search ) + Screen:restoreFromSavedBB() if search ~= nil and string.len( search ) > 0 then unireader:searchHighLight(search)