Merge pull request #152 from houqp/new_ui_code

half done menu widget for new ui framework
pull/2/merge
Dobrica Pavlinušić 12 years ago
commit 76f8b2bdd9

@ -20,6 +20,20 @@
#include <string.h>
#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},

@ -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)

@ -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
)

@ -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

@ -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

@ -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))

@ -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

@ -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))

@ -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"

@ -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");

@ -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))

@ -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)

@ -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

@ -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()

Loading…
Cancel
Save