diff --git a/blitbuffer.c b/blitbuffer.c index 6c6ab70cf..cf4c8c107 100644 --- a/blitbuffer.c +++ b/blitbuffer.c @@ -20,6 +20,20 @@ #include #include "blitbuffer.h" + +inline int setPixel(BlitBuffer *bb, int x, int y, int c) { + uint8_t *dstptr = (uint8_t*)(bb->data) + (y * bb->pitch) + (x / 2); + + if(x % 2 == 0) { + *dstptr &= 0x0F; + *dstptr |= c << 4; + } else { + *dstptr &= 0xF0; + *dstptr |= c; + } + return 0; +} + int newBlitBufferNative(lua_State *L, int w, int h, BlitBuffer **newBuffer) { BlitBuffer *bb = (BlitBuffer*) lua_newuserdata(L, sizeof(BlitBuffer)); luaL_getmetatable(L, "blitbuffer"); @@ -78,7 +92,6 @@ static int blitFullToBuffer(lua_State *L) { } memcpy(dst->data, src->data, src->pitch * src->h); - return 0; } @@ -485,6 +498,172 @@ static int dimRect(lua_State *L) { return 0; } +/* + * @r: radius + * @c: color of the line to draw + * @w: width of the line to draw + */ +static int paintCircle(lua_State *L) { + BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer"); + int center_x = luaL_checkint(L, 2); + int center_y = luaL_checkint(L, 3); + int r = luaL_checkint(L, 4); + int c = luaL_optint(L, 5, 15); + int w = luaL_optint(L, 6, r); + + if( (center_x + r > dst->h) || (center_x - r < 0) || + (center_y + r > dst->w) || (center_y - r < 0) || + (r == 0)) { + return 0; + } + if(w > r) { + w = r; + } + + + int tmp_y; + /* for outer circle */ + int x = 0, y = r; + float delta = 5/4 - r; + /* for inter circle */ + int r2 = r - w; + int x2 = 0, y2 = r2; + float delta2 = 5/4 - r; + + /* draw two axles */ + for(tmp_y = r; tmp_y > r2; tmp_y--) { + setPixel(dst, center_x+0, center_y+tmp_y, c); + setPixel(dst, center_x-0, center_y-tmp_y, c); + setPixel(dst, center_x+tmp_y, center_y+0, c); + setPixel(dst, center_x-tmp_y, center_y-0, c); + } + + while(x < y) { + /* decrease y if we are out of circle */ + x++; + if (delta > 0) { + y--; + delta = delta + 2*x - 2*y + 2; + } else { + delta = delta + 2*x + 1; + } + + /* inner circle finished drawing, increase y linearly for filling */ + if(x2 > y2) { + y2++; + x2++; + } else { + x2++; + if (delta2 > 0) { + y2--; + delta2 = delta2 + 2*x2 - 2*y2 + 2; + } else { + delta2 = delta2 + 2*x2 + 1; + } + } + + for(tmp_y = y; tmp_y > y2; tmp_y--) { + setPixel(dst, center_x+x, center_y+tmp_y, c); + setPixel(dst, center_x+tmp_y, center_y+x, c); + + setPixel(dst, center_x+tmp_y, center_y-x, c); + setPixel(dst, center_x+x, center_y-tmp_y, c); + + setPixel(dst, center_x-x, center_y-tmp_y, c); + setPixel(dst, center_x-tmp_y, center_y-x, c); + + setPixel(dst, center_x-tmp_y, center_y+x, c); + setPixel(dst, center_x-x, center_y+tmp_y, c); + } + } + if(r == w) { + setPixel(dst, center_x, center_y, c); + } + return 0; +} + +static int paintRoundedCorner(lua_State *L) { + BlitBuffer *dst = (BlitBuffer*) luaL_checkudata(L, 1, "blitbuffer"); + int off_x = luaL_checkint(L, 2); + int off_y = luaL_checkint(L, 3); + int w = luaL_checkint(L, 4); + int h = luaL_checkint(L, 5); + int bw = luaL_checkint(L, 6); + int r = luaL_checkint(L, 7); + int c = luaL_optint(L, 8, 15); + + if((2*r > h) || (2*r > w) || (r == 0)) { + return 0; + } + if(r > h) { + r = h; + } + if(r > w) { + r = w; + } + if(bw > r) { + bw = r; + } + + + int tmp_y; + /* for outer circle */ + int x = 0, y = r; + float delta = 5/4 - r; + /* for inter circle */ + int r2 = r - bw; + int x2 = 0, y2 = r2; + float delta2 = 5/4 - r; + + /* draw two axles */ + /*for(tmp_y = r; tmp_y > r2; tmp_y--) {*/ + /*setPixel(dst, (w-r)+off_x+0, (h-r)+off_y+tmp_y-1, c);*/ + /*setPixel(dst, (w-r)+off_x-0, (r)+off_y-tmp_y, c);*/ + /*setPixel(dst, (w-r)+off_x+tmp_y, (h-r)+off_y+0, c);*/ + /*setPixel(dst, (r)+off_x-tmp_y, (h-r)+off_y-0-1, c);*/ + /*}*/ + + while(x < y) { + /* decrease y if we are out of circle */ + x++; + if (delta > 0) { + y--; + delta = delta + 2*x - 2*y + 2; + } else { + delta = delta + 2*x + 1; + } + + /* inner circle finished drawing, increase y linearly for filling */ + if(x2 > y2) { + y2++; + x2++; + } else { + x2++; + if (delta2 > 0) { + y2--; + delta2 = delta2 + 2*x2 - 2*y2 + 2; + } else { + delta2 = delta2 + 2*x2 + 1; + } + } + + for(tmp_y = y; tmp_y > y2; tmp_y--) { + setPixel(dst, (w-r)+off_x+x-1, (h-r)+off_y+tmp_y-1, c); + setPixel(dst, (w-r)+off_x+tmp_y-1, (h-r)+off_y+x-1, c); + + setPixel(dst, (w-r)+off_x+tmp_y-1, (r)+off_y-x, c); + setPixel(dst, (w-r)+off_x+x-1, (r)+off_y-tmp_y, c); + + setPixel(dst, (r)+off_x-x, (r)+off_y-tmp_y, c); + setPixel(dst, (r)+off_x-tmp_y, (r)+off_y-x, c); + + setPixel(dst, (r)+off_x-tmp_y, (h-r)+off_y+x-1, c); + setPixel(dst, (r)+off_x-x, (h-r)+off_y+tmp_y-1, c); + } + } + return 0; +} + static const struct luaL_Reg blitbuffer_func[] = { {"new", newBlitBuffer}, {NULL, NULL} @@ -497,6 +676,8 @@ static const struct luaL_Reg blitbuffer_meth[] = { {"addblitFrom", addblitToBuffer}, {"blitFullFrom", blitFullToBuffer}, {"paintRect", paintRect}, + {"paintCircle", paintCircle}, + {"paintRoundedCorner", paintRoundedCorner}, {"invertRect", invertRect}, {"dimRect", dimRect}, {"free", freeBlitBuffer}, diff --git a/commands.lua b/commands.lua index 2168fb57d..83e2381cf 100644 --- a/commands.lua +++ b/commands.lua @@ -166,6 +166,7 @@ function Commands:new(obj) "toggle screen saver", function() Screen:saveCurrentBB() + InfoMessage:show("Going into screensaver... ", 0) Screen.kpv_rotation_mode = Screen.cur_rotation_mode fb:setOrientation(Screen.native_rotation_mode) util.sleep(1) diff --git a/crereader.lua b/crereader.lua index 8b0f14a4f..d59a35722 100644 --- a/crereader.lua +++ b/crereader.lua @@ -304,45 +304,45 @@ function CREReader:adjustCreReaderCommands() self.commands:del(KEY_D, nil, "D") self.commands:del(KEY_D, MOD_SHIFT, "D") self.commands:del(KEY_D, MOD_ALT, "D") + self.commands:del(KEY_X, nil, "X") self.commands:del(KEY_F, MOD_SHIFT, "F") self.commands:del(KEY_F, MOD_ALT, "F") self.commands:del(KEY_N, nil, "N") -- highlight self.commands:del(KEY_N, MOD_SHIFT, "N") -- show highlights -- overwrite commands - self.commands:add({KEY_PGFWD, KEY_LPGFWD}, MOD_SHIFT, ">", - "increase font size", + + self.commands:addGroup(MOD_SHIFT.."< >",{ + Keydef:new(KEY_PGBCK,MOD_SHIFT),Keydef:new(KEY_PGFWD,MOD_SHIFT), + Keydef:new(KEY_LPGBCK,MOD_SHIFT),Keydef:new(KEY_LPGFWD,MOD_SHIFT)}, + "increase/decrease font size", function(self) - self.doc:zoomFont(1) - self:redrawCurrentPage() - end - ) - self.commands:add({KEY_PGBCK, KEY_LPGBCK}, MOD_SHIFT, "<", - "decrease font size", - function(self) - self.doc:zoomFont(-1) - self:redrawCurrentPage() - end - ) - self.commands:add({KEY_PGFWD, KEY_LPGFWD}, MOD_ALT, ">", - "increase line spacing", - function(self) - self.line_space_percent = self.line_space_percent + 10 - if self.line_space_percent > 200 then - self.line_space_percent = 200 + local delta = 1 + local change = "increase" + if keydef.keycode == KEY_PGBCK or keydef.keycode == KEY_LPGBCK then + delta = -1 + change = "decrease" end - InfoMessage:show("line spacing "..self.line_space_percent.."%", 0) - debug("line spacing set to", self.line_space_percent) - self.doc:setDefaultInterlineSpace(self.line_space_percent) + InfoMessage:show(change.." font size", 0) + self.doc:zoomFont(delta) self:redrawCurrentPage() end ) - self.commands:add({KEY_PGBCK, KEY_LPGBCK}, MOD_ALT, "<", - "decrease line spacing", + self.commands:addGroup(MOD_ALT.."< >",{ + Keydef:new(KEY_PGBCK,MOD_ALT),Keydef:new(KEY_PGFWD,MOD_ALT), + Keydef:new(KEY_LPGBCK,MOD_ALT),Keydef:new(KEY_LPGFWD,MOD_ALT)}, + "increase/decrease line spacing", function(self) - self.line_space_percent = self.line_space_percent - 10 - if self.line_space_percent < 100 then - self.line_space_percent = 100 + if keydef.keycode == KEY_PGBCK or keydef.keycode == KEY_LPGBCK then + self.line_space_percent = self.line_space_percent - 10 + if self.line_space_percent < 100 then + self.line_space_percent = 100 + end + else + self.line_space_percent = self.line_space_percent + 10 + if self.line_space_percent > 200 then + self.line_space_percent = 200 + end end InfoMessage:show("line spacing "..self.line_space_percent.."%", 0) debug("line spacing set to", self.line_space_percent) @@ -378,11 +378,11 @@ function CREReader:adjustCreReaderCommands() local item_no = fonts_menu:choose(0, G_height) debug(face_list[item_no]) if item_no then + Screen:restoreFromSavedBB() self.doc:setFontFace(face_list[item_no]) self.font_face = face_list[item_no] InfoMessage:show("Redrawing with "..face_list[item_no], 0) end - Screen:restoreFromSavedBB() self:redrawCurrentPage() end ) diff --git a/dialog.lua b/dialog.lua index 222f9760c..19f7b0043 100644 --- a/dialog.lua +++ b/dialog.lua @@ -52,18 +52,23 @@ function FocusManager:onFocusMove(args) local current_item = self.layout[self.selected.y][self.selected.x] while true do - if self.selected.y + dy > #self.layout - or self.selected.y + dy < 1 - or self.selected.x + dx > #self.layout[self.selected.y] + if self.selected.x + dx > #self.layout[self.selected.y] or self.selected.x + dx < 1 then - break -- abort when we run into borders + break -- abort when we run into horizontal borders end + -- move cyclic in vertical direction + if self.selected.y + dy > #self.layout then + self.selected.y = 1 + elseif self.selected.y + dy < 1 then + self.selected.y = #self.layout + else + self.selected.y = self.selected.y + dy + end self.selected.x = self.selected.x + dx - self.selected.y = self.selected.y + dy if self.layout[self.selected.y][self.selected.x] ~= current_item - and not self.layout[self.selected.y][self.selected.x].is_inactive then + or not self.layout[self.selected.y][self.selected.x].is_inactive then -- we found a different object to focus current_item:handleEvent(Event:new("Unfocus")) self.layout[self.selected.y][self.selected.x]:handleEvent(Event:new("Focus")) @@ -89,22 +94,24 @@ function Button:init() -- set FrameContainer content self[1] = FrameContainer:new{ margin = 0, - bordersize = 4, + bordersize = 3, background = 0, + radius = 15, + padding = 2, HorizontalGroup:new{ - Widget:new{ dimen = { w = 10, h = 0 } }, + HorizontalSpan:new{ width = 8 }, TextWidget:new{ text = self.text, face = Font:getFace("cfont", 20) }, - Widget:new{ dimen = { w = 10, h = 0 } } + HorizontalSpan:new{ width = 8 }, } } if self.preselect then self[1].color = 15 else - self[1].color = 0 + self[1].color = 5 end end @@ -114,7 +121,7 @@ function Button:onFocus() end function Button:onUnfocus() - self[1].color = 0 + self[1].color = 5 return true end @@ -127,6 +134,8 @@ ConfirmBox = FocusManager:new{ width = nil, ok_text = "OK", cancel_text = "Cancel", + ok_callback = function() end, + cancel_callback = function() end, } function ConfirmBox:init() @@ -154,6 +163,7 @@ function ConfirmBox:init() FrameContainer:new{ margin = 2, background = 0, + padding = 10, HorizontalGroup:new{ ImageWidget:new{ file = "resources/info-i.png" @@ -169,8 +179,8 @@ function ConfirmBox:init() VerticalSpan:new{ width = 10 }, HorizontalGroup:new{ ok_button, - Widget:new{ dimen = { w = 10, h = 0 } }, - cancel_button + HorizontalSpan:new{ width = 10 }, + cancel_button, } } } @@ -184,7 +194,12 @@ function ConfirmBox:onClose() end function ConfirmBox:onSelect() - print("selected:", self.selected.x) + debug("selected:", self.selected.x) + if self.selected.x == 1 then + self:ok_callback() + else + self:cancel_callback() + end UIManager:close(self) return true end @@ -217,10 +232,8 @@ function InfoMessage:init() ImageWidget:new{ file = "resources/info-i.png" }, - Widget:new{ - dimen = { w = 10, h = 0 } - }, - TextWidget:new{ + HorizontalSpan:new{ width = 10 }, + TextBoxWidget:new{ text = self.text, face = Font:getFace("cfont", 30) } @@ -242,3 +255,276 @@ function InfoMessage:onAnyKeyPressed() UIManager:close(self) return true end + + +--[[ +Widget that displays a shortcut icon for menu item +]] +ItemShortCutIcon = WidgetContainer:new{ + width = 22, + height = 22, + key = nil, + bordersize = 2, +} + +function ItemShortCutIcon:init() + if not self.key then + return + end + self[1] = HorizontalGroup:new{ + HorizontalSpan:new{ width = 5 }, + FrameContainer:new{ + padding = 0, + bordersize = self.bordersize, + dimen = { + w = self.width, + h = self.height, + }, + CenterContainer:new{ + dimen = { + w = self.width, + h = self.height, + }, + TextWidget:new{ + text = self.key, + face = Font:getFace("scfont", 22) + }, + }, + }, + HorizontalSpan:new{ width = 5 }, + } +end + + +--[[ +Widget that displays an item for menu + +]] +MenuItem = WidgetContainer:new{ + text = nil, + detail = nil, + face = Font:getFace("cfont", 22), + width = nil, + height = nil, + shortcut = nil, +} + +function MenuItem:init() + local shortcut_icon_w = 0 + local shortcut_icon_h = 0 + if self.shortcut then + shortcut_icon_w = math.floor(self.height*4/5) + shortcut_icon_h = shortcut_icon_w + end + + self.detail = self.text + w = sizeUtf8Text(0, self.width, self.face, self.text, true).x + if w >= self.width - shortcut_icon_w then + indicator = " >>" + indicator_w = sizeUtf8Text(0, self.width, self.face, indicator, true).x + self.text = getSubTextByWidth(self.text, self.face, + self.width - shortcut_icon_w - indicator_w - 4, true) .. indicator + end + + self[1] = HorizontalGroup:new{ + ItemShortCutIcon:new{ + width = shortcut_icon_w, + height = shortcut_icon_h, + key = self.shortcut, + }, + HorizontalSpan:new{ width = 5 }, + UnderlineContainer:new{ + dimen = { + w = self.width - 5 - shortcut_icon_w, + h = self.height + }, + HorizontalGroup:new { + align = "center", + TextWidget:new{ + text = self.text, + face = self.face, + }, + }, + }, + } +end + +function MenuItem:onFocus() + self[1][3].color = 10 + return true +end + +function MenuItem:onUnfocus() + self[1][3].color = 0 + return true +end + +function MenuItem:onShowDetail() + UIManager:show(InfoMessage:new{ + text=self.detail, + }) + return true +end + + +--[[ +Widget that displays menu +]] +Menu = FocusManager:new{ + -- face for displaying item contents + cface = Font:getFace("cfont", 22), + -- face for menu title + tface = Font:getFace("tfont", 25), + -- face for paging info display + fface = Font:getFace("ffont", 16), + -- font for item shortcut + sface = Font:getFace("scfont", 20), + + title = "No Title", + height = 500, + width = 500, + item_table = {}, + items = 0, + item_shortcuts = { + "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", + "A", "S", "D", "F", "G", "H", "J", "K", "L", "Del", + "Z", "X", "C", "V", "B", "N", "M", ".", "Sym", "Enter", + }, + is_enable_shortcut = true, + + item_height = 36, + page = 1, + current = 1, + oldcurrent = 0, + selected_item = nil, +} + +function Menu:init() + self.items = #self.item_table + self.perpage = math.floor(self.height / self.item_height) + self.page = 1 + self.page_num = math.ceil(self.items / self.perpage) + + self.key_events.Close = { {"Back"}, doc = "close menu" } + self.key_events.Select = { {"Press"}, doc = "chose selected item" } + self.key_events.NextPage = { + {Input.group.PgFwd}, doc = "goto next page of the menu" + } + self.key_events.PrevPage = { + {Input.group.PgBack}, doc = "goto previous page of the menu" + } + self.key_events.FocusRight = nil + self.key_events.ShowItemDetail = { {"Right"}, doc = "show item detail" } + if self.is_enable_shortcut then + self.key_events.SelectByShortCut = { {self.item_shortcuts} } + end + + self[1] = CenterContainer:new{ + dimen = {w = G_width, h = G_height}, + FrameContainer:new{ + background = 0, + radius = math.floor(self.width/20), + VerticalGroup:new{ + TextWidget:new{ + text = self.title, + face = self.tface, + }, + -- group for items + VerticalGroup:new{ + }, + TextWidget:new{ + text = "page "..self.page.."/"..self.page_num, + face = self.fface, + }, + VerticalSpan:new{ width = 5 }, + }, -- VerticalGroup + }, -- FrameContainer + } -- CenterContainer + + self:_updateItems() +end + +function Menu:_updateItems() + self.layout = {} + self[1][1][1][2] = VerticalGroup:new{} + local item_group = self[1][1][1][2] + + for c = 1, self.perpage do + local i = (self.page - 1) * self.perpage + c + if i <= self.items then + local item_shortcut = nil + if self.is_enable_shortcut then + item_shortcut = self.item_shortcuts[c] + if item_shortcut == "Enter" then + item_shortcut = "Ent" + end + end + item_tmp = MenuItem:new{ + text = self.item_table[i].text, + face = self.cface, + width = self.width - 14, + height = self.item_height, + shortcut = item_shortcut + } + table.insert(item_group, item_tmp) + table.insert(self.layout, {item_tmp}) + --self.last_shortcut = c + end -- if i <= self.items + end -- for c=1, self.perpage + -- set focus to first menu item + item_group[1]:onFocus() +end + +function Menu:onSelectByShortCut(_, keyevent) + for k,v in ipairs(self.item_shortcuts) do + if v == keyevent.key then + local item = self.item_table[k] + self.item_table = nil + UIManager:close(self) + debug(item) + -- send events + break + end + end +end + +function Menu:onNextPage() + if self.page < self.page_num then + local page_info = self[1][1][1][3] + self.page = self.page + 1 + self:_updateItems() + self.selected = { x = 1, y = 1 } + self[1][1][1][3] = TextWidget:new{ + text = "page "..self.page.."/"..self.page_num, + face = self.fface, + }, + UIManager:setDirty(self) + end + return true +end + +function Menu:onPrevPage() + if self.page > 1 then + local page_info = self[1][1][1][3] + self.page = self.page - 1 + self:_updateItems() + self.selected = { x = 1, y = 1 } + self[1][1][1][3] = TextWidget:new{ + text = "page "..self.page.."/"..self.page_num, + face = self.fface, + }, + UIManager:setDirty(self) + end + return true +end + +function Menu:onShowItemDetail() + return self.layout[self.selected.y][self.selected.x]:handleEvent( + Event:new("ShowDetail") + ) +end + +function Menu:onClose() + UIManager:close(self) + return true +end diff --git a/filechooser.lua b/filechooser.lua index 688160ddd..0e4ff59a2 100644 --- a/filechooser.lua +++ b/filechooser.lua @@ -169,7 +169,7 @@ function FileChooser:choose(ypos, height) local ev = input.saveWaitForEvent() --debug("key code:"..ev.code) ev.code = adjustKeyEvents(ev) - if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then + if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then if ev.code == KEY_FW_UP then prevItem() elseif ev.code == KEY_FW_DOWN then diff --git a/filesearcher.lua b/filesearcher.lua index d3c7827f5..f36d14152 100644 --- a/filesearcher.lua +++ b/filesearcher.lua @@ -292,7 +292,7 @@ function FileSearcher:choose(keywords) local ev = input.saveWaitForEvent() ev.code = adjustKeyEvents(ev) - if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then + if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then keydef = Keydef:new(ev.code, getKeyModifier()) debug("key pressed: "..tostring(keydef)) diff --git a/graphics.lua b/graphics.lua index 267cb9469..562bdd995 100644 --- a/graphics.lua +++ b/graphics.lua @@ -1,12 +1,33 @@ +--[[ +Draw a border -blitbuffer.paintBorder = function (bb, x, y, w, h, bw, c) - bb:paintRect(x, y, w, bw, c) - bb:paintRect(x, y+h-bw, w, bw, c) - bb:paintRect(x, y+bw, bw, h - 2*bw, c) - bb:paintRect(x+w-bw, y+bw, bw, h - 2*bw, c) +@x: start position in x axis +@y: start position in y axis +@w: width of the border +@h: height of the border +@bw: line width of the border +@c: color for loading bar +@r: radius of for border's corner (nil or 0 means right corner border) +--]] +function blitbuffer.paintBorder(bb, x, y, w, h, bw, c, r) + if not r or r == 0 then + bb:paintRect(x, y, w, bw, c) + bb:paintRect(x, y+h-bw, w, bw, c) + bb:paintRect(x, y+bw, bw, h - 2*bw, c) + bb:paintRect(x+w-bw, y+bw, bw, h - 2*bw, c) + else + if h < 2*r then h = 2 * r end + if w < 2*r then w = 2 * r end + bb:paintRoundedCorner(x, y, w, h, bw, r, c) + bb:paintRect(r+x, y, w-2*r, bw, c) + bb:paintRect(r+x, y+h-bw, w-2*r, bw, c) + bb:paintRect(x, r+y, bw, h-2*r, c) + bb:paintRect(x+w-bw, r+y, bw, h-2*r, c) + end end + --[[ Draw a progress bar according to following args: @@ -19,8 +40,8 @@ Draw a progress bar according to following args: @load_percent: progress in percent @c: color for loading bar --]] -blitbuffer.progressBar = function (bb, x, y, w, h, - load_m_w, load_m_h, load_percent, c) +function blitbuffer.progressBar(bb, x, y, w, h, + load_m_w, load_m_h, load_percent, c) if load_m_h*2 > h then load_m_h = h/2 end diff --git a/inputbox.lua b/inputbox.lua index 239267d5b..34339841d 100644 --- a/inputbox.lua +++ b/inputbox.lua @@ -185,7 +185,7 @@ function InputBox:input(ypos, height, title, d_text, is_hint) while true do local ev = input.saveWaitForEvent() ev.code = adjustKeyEvents(ev) - if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then + if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then keydef = Keydef:new(ev.code, getKeyModifier()) debug("key pressed: "..tostring(keydef)) diff --git a/inputevent.lua b/inputevent.lua index 9d248f9e2..af27c3f05 100644 --- a/inputevent.lua +++ b/inputevent.lua @@ -183,6 +183,8 @@ Input = { -- these groups are just helpers: group = { Cursor = { "Up", "Down", "Left", "Right" }, + PgFwd = { "RPgFwd", "LPgFwd" }, + PgBack = { "RPgBack", "LPgBack" }, Alphabet = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" diff --git a/rendertext.lua b/rendertext.lua index 68e4aa8ce..2e70c3bf4 100644 --- a/rendertext.lua +++ b/rendertext.lua @@ -44,6 +44,30 @@ function clearGlyphCache() glyphcache = {} end +function getSubTextByWidth(text, face, width, kerning) + local pen_x = 0 + local prevcharcode = 0 + local char_list = {} + for uchar in string.gfind(text, "([%z\1-\127\194-\244][\128-\191]*)") do + if pen_x < width then + local charcode = util.utf8charcode(uchar) + local glyph = getGlyph(face, charcode) + if kerning and prevcharcode then + local kern = face.ftface:getKerning(prevcharcode, charcode) + pen_x = pen_x + kern + end + pen_x = pen_x + glyph.ax + if pen_x <= width then + prevcharcode = charcode + table.insert(char_list, uchar) + else + break + end + end + end + return table.concat(char_list) +end + function sizeUtf8Text(x, width, face, text, kerning) if text == nil then debug("sizeUtf8Text called without text"); diff --git a/selectmenu.lua b/selectmenu.lua index 186f6fb4d..dae914d0d 100644 --- a/selectmenu.lua +++ b/selectmenu.lua @@ -317,7 +317,7 @@ function SelectMenu:choose(ypos, height) local ev = input.saveWaitForEvent() ev.code = adjustKeyEvents(ev) - if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then + if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then keydef = Keydef:new(ev.code, getKeyModifier()) debug("key pressed: "..tostring(keydef)) diff --git a/unireader.lua b/unireader.lua index 81cef0f3f..4ff82b109 100644 --- a/unireader.lua +++ b/unireader.lua @@ -40,6 +40,7 @@ UniReader = { -- size of current page for current zoom level in pixels cur_full_width = 0, cur_full_height = 0, + cur_bbox = {}, -- current page bbox offset_x = 0, offset_y = 0, dest_x = 0, -- real offset_x when it's smaller than screen, so it's centered @@ -54,7 +55,7 @@ UniReader = { pan_by_page = false, -- using shift_[xy] or width/height pan_x = 0, -- top-left offset of page when pan activated pan_y = 0, - pan_margin = 20, -- horizontal margin for two-column zoom + pan_margin = 5, -- horizontal margin for two-column zoom (in pixels) pan_overlap_vertical = 30, show_overlap = 0, @@ -555,7 +556,7 @@ function UniReader:startHighLightMode() while running do local ev = input.saveWaitForEvent() ev.code = adjustKeyEvents(ev) - if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then + if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then if ev.code == KEY_FW_LEFT and not is_meet_start then is_meet_end = false l.new, w.new, is_meet_start = _prevGap(t, l.cur, w.cur) @@ -779,7 +780,7 @@ function UniReader:startHighLightMode() while running do local ev = input.saveWaitForEvent() ev.code = adjustKeyEvents(ev) - if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then + if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then if ev.code == KEY_FW_LEFT then is_meet_end = false if not is_meet_start then @@ -1260,13 +1261,11 @@ function UniReader:setzoom(page, preCache) or self.globalzoom_mode == self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH_MARGIN then local margin = self.pan_margin if self.globalzoom_mode == self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH then margin = 0 end - local pg_margin = 0 -- margin scaled to page size - if margin > 0 then pg_margin = margin * 2 / self.globalzoom end - self.globalzoom = width / (x1 - x0 + pg_margin) + self.globalzoom = width / (x1 - x0 + margin) self.offset_x = -1 * x0 * self.globalzoom * 2 + margin - self.globalzoom = height / (y1 - y0 + pg_margin) + self.globalzoom = height / (y1 - y0 + margin) self.offset_y = -1 * y0 * self.globalzoom * 2 + margin - self.globalzoom = width / (x1 - x0 + pg_margin) * 2 + self.globalzoom = width / (x1 - x0 + margin) * 2 debug("column mode offset:", self.offset_x, self.offset_y, " zoom:", self.globalzoom); self.globalzoom_mode = self.ZOOM_BY_VALUE -- enable pan mode self.pan_x = self.offset_x @@ -1282,6 +1281,15 @@ function UniReader:setzoom(page, preCache) if not preCache then -- save current page fullsize self.cur_full_width = self.fullwidth self.cur_full_height = self.fullheight + + self.cur_bbox = { + ["x0"] = x0, + ["y0"] = y0, + ["x1"] = x1, + ["y1"] = y1, + } + debug("cur_bbox", self.cur_bbox) + end self.min_offset_x = fb.bb:getWidth() - self.fullwidth self.min_offset_y = fb.bb:getHeight() - self.fullheight @@ -1784,7 +1792,7 @@ function UniReader:inputLoop() while 1 do local ev = input.saveWaitForEvent() ev.code = adjustKeyEvents(ev) - if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then + if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then local secs, usecs = util.gettime() keydef = Keydef:new(ev.code, getKeyModifier()) debug("key pressed:", tostring(keydef)) @@ -1802,6 +1810,13 @@ function UniReader:inputLoop() local nsecs, nusecs = util.gettime() local dur = (nsecs - secs) * 1000000 + nusecs - usecs debug("E: T="..ev.type, " V="..ev.value, " C="..ev.code, " DUR=", dur) + + if ev.value == EVENT_VALUE_KEY_REPEAT then + self.rcount = 0 + debug("prevent full screen refresh", self.rcount) + end + else + debug("ignored ev ",ev) end end @@ -2067,6 +2082,16 @@ function UniReader:addAllCommands() end debug("bbox override", unireader.bbox.enabled); end) + self.commands:add(KEY_X,nil,"X", + "invert page bbox", + function(unireader) + local bbox = unireader.cur_bbox + debug("bbox", bbox) + x,y,w,h = unireader:getRectInScreen( bbox["x0"], bbox["y0"], bbox["x1"], bbox["y1"] ) + debug("inxertRect",x,y,w,h) + fb.bb:invertRect( x,y, w,h ) + fb:refresh(0) + end) self.commands:add(KEY_MENU,nil,"Menu", "toggle info box", function(unireader) diff --git a/widget.lua b/widget.lua index b7046ae7b..a624d7bca 100644 --- a/widget.lua +++ b/widget.lua @@ -85,8 +85,8 @@ end Containers will pass events to children or react on them themselves ]] function WidgetContainer:handleEvent(event) - -- call our own standard event handler if not self:propagateEvent(event) then + -- call our own standard event handler return Widget.handleEvent(self, event) else return true @@ -124,6 +124,7 @@ FrameContainer = WidgetContainer:new{ background = nil, color = 15, margin = 0, + radius = 0, bordersize = 2, padding = 5, } @@ -145,7 +146,7 @@ function FrameContainer:paintTo(bb, x, y) if self.bordersize > 0 then bb:paintBorder(x + self.margin, y + self.margin, my_size.w - self.margin * 2, my_size.h - self.margin * 2, - self.bordersize, self.color) + self.bordersize, self.color, self.radius) end if self[1] then self[1]:paintTo(bb, @@ -167,9 +168,9 @@ TextWidget = Widget:new{ } function TextWidget:_render() - local h = self.face.size * 1.5 + local h = self.face.size * 1.3 self._bb = Blitbuffer.new(self._maxlength, h) - self._length = renderUtf8Text(self._bb, 0, h*.7, self.face, self.text, self.color) + self._length = renderUtf8Text(self._bb, 0, h*0.8, self.face, self.text, self.color) end function TextWidget:getSize() @@ -256,15 +257,19 @@ function TextBoxWidget:_render() local h = (font_height + line_height_px) * #v_list - line_height_px self._bb = Blitbuffer.new(self.width, h) local y = font_height - + local pen_x = 0 for _,l in ipairs(v_list) do - local pen_x = 0 + pen_x = 0 for _,w in ipairs(l) do - renderUtf8Text(self._bb, pen_x, y, self.face, w.word, true) + renderUtf8Text(self._bb, pen_x, y*0.8, self.face, w.word, true) pen_x = pen_x + w.width + space_w end y = y + line_height_px + font_height end + -- if text is shorter than one line, shrink to text's width + if #v_list == 1 then + self.width = pen_x + end end function TextBoxWidget:getSize() @@ -454,13 +459,17 @@ UnderlineContainer = WidgetContainer:new{ function UnderlineContainer:getSize() local contentSize = self[1]:getSize() + if self.dimen then + if contentSize.w < self.dimen.w then contentSize.w = self.dimen.w end + if contentSize.h < self.dimen.h then contentSize.h = self.dimen.h end + end return { w = contentSize.w, h = contentSize.h + self.linesize + self.padding } end function UnderlineContainer:paintTo(bb, x, y) - local contentSize = self[1]:getSize() + local contentSize = self:getSize() self[1]:paintTo(bb, x, y) - bb:paintRect(x, y + contentSize.h + self.padding, + bb:paintRect(x, y + contentSize.h - self.linesize, contentSize.w, self.linesize, self.color) end diff --git a/wtest.lua b/wtest.lua index 36ea9269c..8c6e861b6 100644 --- a/wtest.lua +++ b/wtest.lua @@ -71,15 +71,42 @@ function Clock:getTextWidget() } end -quiz = ConfirmBox:new{ +Quiz = ConfirmBox:new{ text = "Tell me the truth, isn't it COOL?!", width = 300, ok_text = "Yes, of course.", cancel_text = "No, it's ugly.", + cancel_callback = function() + UIManager:show(InfoMessage:new{ + text="You liar!", + }) + end, +} + +menu_items = { + {text = "item1"}, + {text = "item2"}, + {text = "This is a very very log item whose length should exceed the width of the menu."}, + {text = "item3"}, + {text = "item4"}, + {text = "item5"}, + {text = "item6"}, + {text = "item7"}, + {text = "item8"}, + {text = "item9"}, + {text = "item10"}, + {text = "item11"}, + {text = "item12"}, +} +M = Menu:new{ + title = "Test Menu", + item_table = menu_items, + width = 500, + height = 400, } -quiz:init() UIManager:show(Background:new()) UIManager:show(Clock:new()) -UIManager:show(quiz) +UIManager:show(M) +UIManager:show(Quiz) UIManager:run()