mod: rewrite highlight feature

pull/2/merge
Qingping Hou 12 years ago
parent f4ea1cdb62
commit a185f238eb

@ -247,6 +247,19 @@ static int getUsedBBox(lua_State *L) {
* x0 = 377, y0 = 4857, x1 = 2427, y1 = 5089,
* },
* }
*
* 5 words in two lines
* {
* 1 = {word="This", x0=377, y0=4857, x1=2427, y1=5089},
* 2 = {word="This", x0=377, y0=4857, x1=2427, y1=5089},
* 3 = {word="This", x0=377, y0=4857, x1=2427, y1=5089},
* 4 = {word="This", x0=377, y0=4857, x1=2427, y1=5089},
* 5 = {word="This", x0=377, y0=4857, x1=2427, y1=5089},
* lines = {
* 1 = {last = 2, x0 = 377, y0 = 4857, x1 = 2427, y1 = 5089},
* 2 = {last = 5, x0 = 377, y0 = 4857, x1 = 2427, y1 = 5089},
* }
* }
*/
static int getPageText(lua_State *L) {
DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument");
@ -267,10 +280,16 @@ static int getPageText(lua_State *L) {
sexp = miniexp_cdr(sexp);
/* get number of lines in a page */
nr_line = miniexp_length(sexp);
/* table that contains all the lines */
/* the outer table */
lua_newtable(L);
/* create lines subtable */
lua_pushstring(L, "lines");
lua_newtable(L);
lua_settable(L, -3);
counter_l = 1;
counter_w = 1;
for(i = 1; i <= nr_line; i++) {
/* retrive one line entry */
se_line = miniexp_nth(i, sexp);
@ -279,32 +298,7 @@ static int getPageText(lua_State *L) {
continue;
}
/* subtable that contains words in a line */
lua_pushnumber(L, counter_l);
lua_newtable(L);
counter_l++;
/* set line position */
lua_pushstring(L, "x0");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(1, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "y0");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(2, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "x1");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(3, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "y1");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(4, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "words");
lua_newtable(L);
/* now loop through each word in the line */
counter_w = 1;
for(j = 1; j <= nr_word; j++) {
/* retrive one word entry */
se_word = miniexp_nth(j, se_line);
@ -340,14 +334,44 @@ static int getPageText(lua_State *L) {
lua_pushstring(L, word);
lua_settable(L, -3);
/* set word entry to "words" table */
/* set word entry to outer table */
lua_settable(L, -3);
} /* end of for (j) */
/* set "words" table to line entry table */
/* get lines table from outer table */
lua_pushstring(L, "lines");
lua_getfield(L, -2, "lines");
/* subtable that contains info for a line */
lua_pushnumber(L, counter_l);
lua_newtable(L);
counter_l++;
/* set line position */
lua_pushstring(L, "x0");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(1, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "y0");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(2, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "x1");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(3, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "y1");
lua_pushnumber(L, miniexp_to_int(miniexp_nth(4, se_line)));
lua_settable(L, -3);
lua_pushstring(L, "last");
lua_pushnumber(L, counter_w-1);
lua_settable(L, -3);
/* set line entry to lines subtable */
lua_settable(L, -3);
/* set line entry to page text table */
/* set lines subtable back to outer table */
lua_settable(L, -3);
} /* end of for (i) */

@ -22,6 +22,18 @@ function DJVUReader:_isWordInScreenRange(w)
-self.offset_y ))
end
function DJVUReader:_toggleWordHighLightByEnds(t, end1, end2)
if end1 > end2 then
end1, end2 = end2, end1
end
for i=end1, end2, 1 do
if self:_isWordInScreenRange(t[i]) then
self:_toggleWordHighLight(t[i])
end
end
end
function DJVUReader:_isLastWordInPage(t, l, w)
return (l == #t) and (w == #(t[l].words))
end
@ -79,184 +91,273 @@ function DJVUReader:_genTextIter(text, l0, w0, l1, w1)
return function() count = count + 1 return word_items[count] end
end
function DJVUReader:_drawTextHighLight(text_iter)
for i in text_iter do
fb.bb:invertRect(
i.x0*self.globalzoom,
self.offset_y+self.cur_full_height-(i.y1*self.globalzoom),
(i.x1-i.x0)*self.globalzoom,
(i.y1-i.y0)*self.globalzoom, 15)
end -- EOF for
function DJVUReader:getScreenPosByPagePos()
end
function DJVUReader:_toggleWordHighLight(w)
fb.bb:invertRect(
w.x0*self.globalzoom,
self.offset_y+self.cur_full_height-(w.y1*self.globalzoom),
(w.x1-w.x0)*self.globalzoom,
(w.y1-w.y0)*self.globalzoom, 15)
end
function DJVUReader:startHighLightMode()
local t = self.doc:getPageText(self.pageno)
local function _posToNextWord(t, cur_l, cur_w)
local new_l = cur_l
local new_w = cur_w
if new_w >= #(t[new_l].words) then
if new_l == #t then
-- word to mark is the last word in last line
return new_l, #(t[new_l].words)+1
else
-- word to mark is not the last word in last line,
-- goto next line
new_l = new_l + 1
new_w = 1
--print(dump(t))
local function _getLineByWord(t, cur_w)
for k,l in ipairs(t.lines) do
if l.last >= cur_w then
return k
end
else
-- simply move to next word in the same line
new_w = new_w + 1
end
return new_l, new_w
end
local function _posToPrevWord(t, cur_l, cur_w)
local new_l = cur_l
local new_w = cur_w
if new_w == 1 then
-- already the first word, goto previous line
new_l = new_l - 1
if new_l == 0 or #(t[new_l].words) == 0 then
return cur_l, cur_w
local function _findFirstWordInView(t)
for k,v in ipairs(t) do
if self:_isWordInScreenRange(v) then
return k
end
new_w = #(t[new_l].words)
else
-- simply move to previous word in the same line
new_w = new_w - 1
end
return new_l, new_w
return nil
end
local function _posToNextLine(t, cur_l, cur_w)
local new_l = cur_l
local new_w = cur_w
local function _wordInNextLine(t, cur_w)
local cur_l = _getLineByWord(t, cur_w)
if cur_l == #t.lines then
-- already in last line, return the last word
return t.lines[cur_l].last
else
local next_l_start = t.lines[cur_l].last + 1
local cur_l_start = 1
if cur_l ~= 1 then
cur_l_start = t.lines[cur_l-1].last + 1
end
if new_l >= #t then
-- already last line, jump to line end instead
return new_l, #(t[new_l].words)+1
cur_w = next_l_start + (cur_w - cur_l_start)
if cur_w > t.lines[cur_l+1].last then
cur_w = t.lines[cur_l+1].last
end
return cur_w
end
new_l = new_l + 1
new_w = math.min(new_w, #t[new_l].words)
return new_l, new_w
end
local function _posToPrevLine(t, cur_l, cur_w)
local new_l = cur_l
local new_w = cur_w
local function _wordInPrevLine(t, cur_w)
local cur_l = _getLineByWord(t, cur_w)
if cur_l == 1 then
-- already in first line, return 0
return 0
else
local prev_l_start = 1
if cur_l > 2 then
-- previous line is not the first line
prev_l_start = t.lines[cur_l-2].last + 1
end
local cur_l_start = t.lines[cur_l-1].last + 1
if new_l == 1 then
return cur_l, cur_w
cur_w = prev_l_start + (cur_w - cur_l_start)
if cur_w > t.lines[cur_l-1].last then
cur_w = t.lines[cur_l-1].last
end
return cur_w
end
end
new_l = new_l - 1
new_w = math.min(new_w, #t[new_l].words)
return new_l, new_w
local start_w = _findFirstWordInView(t)
if not start_w then
print("# no text in current view!")
return
end
local start_l = 1
local start_w = 1
-- next to be marked word position
local cur_l = 1
--local cur_w = #(t[1].words)
local cur_w = 1
local new_l = 1
local cur_w = start_w
local new_w = 1
local iter
local meet_page_end = false
local meet_page_start = false
local is_hightlight_mode = false
self.cursor = Cursor:new {
x_pos = t[cur_w].x1*self.globalzoom,
y_pos = self.offset_y + (self.cur_full_height
- (t[cur_w].y1 * self.globalzoom)),
h = (t[cur_w].y1-t[cur_w].y0)*self.globalzoom,
}
self.cursor:draw()
fb:refresh(0)
while true do
local ev = input.waitForEvent()
ev.code = adjustKeyEvents(ev)
if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then
if ev.code == KEY_FW_LEFT then
if self:_isFirstWordInPage(t, cur_l, cur_w) then
iter = function() return nil end
else
new_l, new_w = _posToPrevWord(t, cur_l, cur_w)
if not self:_isWordInScreenRange(t[new_l].words[new_w]) then
-- goto next view of current page
if cur_w >= 1 then
new_w = cur_w - 1
if new_w ~= 0 and
not self:_isWordInScreenRange(t[new_w]) then
-- word is in previous view
local pageno = self:prevView()
self:goto(pageno)
cur_l = start_l
cur_w = start_w
else
self.cursor:clear()
end
-- update cursor
if new_w == 0 then
-- meet top end, must be handled as special case
self.cursor:setHeight((t[1].y1 - t[1].y0)
* self.globalzoom)
self.cursor:moveTo(
t[1].x0*self.globalzoom - self.cursor.w,
self.offset_y + self.cur_full_height
- t[1].y1 * self.globalzoom)
else
self.cursor:setHeight((t[new_w].y1 - t[new_w].y0)
* self.globalzoom)
self.cursor:moveTo(t[new_w].x1*self.globalzoom,
self.offset_y + self.cur_full_height
- (t[new_w].y1*self.globalzoom))
end
iter = self:_genTextIter(t, new_l, new_w, cur_l, cur_w)
meet_page_end = false
self.cursor:draw()
if is_hightlight_mode then
-- update highlight
if new_w ~= 0 and
not self:_isWordInScreenRange(t[new_w]) then
self:_toggleWordHighLightByEnds(t, start_w, new_w)
else
self:_toggleWordHighLight(t[new_w+1])
end
end
cur_w = new_w
end
elseif ev.code == KEY_FW_RIGHT then
if meet_page_end then
iter = function() return nil end
else
new_l, new_w = _posToNextWord(t, cur_l, cur_w)
if not self:_isWordInScreenRange(t[new_l].words[new_w]) then
if self:_isLastWordInPage(t, new_l, new_w-1) then
-- meet the end of page, mark it
meet_page_end = true
else
-- goto next view of current page
-- only highlight word in current page
if cur_w < #t then
new_w = cur_w + 1
if not self:_isWordInScreenRange(t[new_w]) then
local pageno = self:nextView()
self:goto(pageno)
cur_l = start_l
cur_w = start_w
else
self.cursor:clear()
end
-- update cursor
self.cursor:setHeight((t[new_w].y1 - t[new_w].y0)
* self.globalzoom)
self.cursor:moveTo(t[new_w].x1*self.globalzoom,
self.offset_y + self.cur_full_height
- (t[new_w].y1 * self.globalzoom))
self.cursor:draw()
if is_hightlight_mode then
-- update highlight
if not self:_isWordInScreenRange(t[new_w]) then
-- word to highlight is in next view
self:_toggleWordHighLightByEnds(t, start_w, new_w)
else
self:_toggleWordHighLight(t[new_w])
end
end
iter = self:_genTextIter(t, cur_l, cur_w, new_l, new_w)
meet_page_start = false
cur_w = new_w
end
elseif ev.code == KEY_FW_UP then
if self:_isFirstWordInPage(t, cur_l, cur_w) then
iter = function() return nil end
else
new_l, new_w = _posToPrevLine(t, cur_l, cur_w)
if not self:_isWordInScreenRange(t[new_l].words[new_w]) then
new_w = _wordInPrevLine(t, cur_w)
if new_w ~= 0 and
not self:_isWordInScreenRange(t[new_w]) then
-- goto next view of current page
local pageno = self:prevView()
self:goto(pageno)
cur_l = start_l
cur_w = start_w
else
-- no need to jump to next view, clear previous cursor
self.cursor:clear()
end
iter = self:_genTextIter(t, new_l, new_w, cur_l, cur_w)
meet_page_end = false
end
if new_w == 0 then
-- meet top end, must be handled as special case
self.cursor:setHeight((t[1].y1 - t[1].y0)
* self.globalzoom)
self.cursor:moveTo(
t[1].x0*self.globalzoom - self.cursor.w,
self.offset_y + self.cur_full_height
- t[1].y1 * self.globalzoom)
else
self.cursor:setHeight((t[new_w].y1 - t[new_w].y0)
* self.globalzoom)
self.cursor:moveTo(t[new_w].x1*self.globalzoom,
self.offset_y + self.cur_full_height
- (t[new_w].y1*self.globalzoom))
end
self.cursor:draw()
if is_hightlight_mode then
-- update highlight
if new_w ~= 0 and
not self:_isWordInScreenRange(t[new_w]) then
-- word is in previous view
self:_toggleWordHighLightByEnds(t, start_w, new_w)
else
for i=new_w+1, cur_w, 1 do
self:_toggleWordHighLight(t[i])
end
end
end
cur_w = new_w
elseif ev.code == KEY_FW_DOWN then
if meet_page_end then
-- already at the end of page, we don't do a pageturn
-- so do noting here
iter = function() return nil end
new_w = _wordInNextLine(t, cur_w)
if not self:_isWordInScreenRange(t[new_w]) then
-- goto next view of current page
local pageno = self:nextView()
self:goto(pageno)
else
new_l, new_w = _posToNextLine(t, cur_l, cur_w)
if not self:_isWordInScreenRange(t[new_l].words[new_w]) then
if self:_isLastWordInPage(t, new_l, new_w-1) then
-- meet the end of page, mark it
meet_page_end = true
else
-- goto next view of current page
local pageno = self:nextView()
self:goto(pageno)
cur_l = start_l
cur_w = start_w
-- no need to jump to next view, clear previous cursor
self.cursor:clear()
end
-- update cursor
self.cursor:setHeight((t[new_w].y1 - t[new_w].y0)
* self.globalzoom)
self.cursor:moveTo(t[new_w].x1*self.globalzoom,
self.offset_y + self.cur_full_height
- (t[new_w].y1*self.globalzoom))
self.cursor:draw()
if is_hightlight_mode then
-- update highlight
if not self:_isWordInScreenRange(t[new_w]) then
-- redraw from start because of page refresh
self:_toggleWordHighLightByEnds(t, start_w, new_w)
else
-- word in next is in current view, just highlight it
for i=cur_w+1, new_w, 1 do
self:_toggleWordHighLight(t[i])
end
end
iter = self:_genTextIter(t, cur_l, cur_w, new_l, new_w)
meet_page_start = false
end
end -- EOF if keyevent
self:_drawTextHighLight(iter)
cur_w = new_w
elseif ev.code == KEY_FW_PRESS then
if not is_hightlight_mode then
is_hightlight_mode = true
start_w = cur_w
else -- pressed in highlight mode, record selected text
if start_w < cur_w then
self:_toggleWordHighLightByEnds(t, start_w+1, cur_w)
else
self:_toggleWordHighLightByEnds(t, cur_w+1, start_w)
end
is_hightlight_mode = false
end
end -- EOF if keyevent
fb:refresh(0)
cur_l, cur_w = new_l, new_w
end
end -- EOF while
end
end

@ -48,16 +48,20 @@ function Cursor:new(o)
o = o or {}
o.x_pos = o.x_pos or self.x_pos
o.y_pos = o.y_pos or self.y_pos
o.h = o.h or self.h
o.w = o.h / 3
o.line_w = math.floor(o.h / 10)
setmetatable(o, self)
self.__index = self
o:setHeight(o.h or self.h)
return o
end
function Cursor:setHeight(h)
self.h = h
self.w = self.h / 3
self.line_w = math.floor(self.h / 10)
end
function Cursor:_draw(x, y)
local body_h = self.h - self.line_w
-- paint upper horizontal line
@ -96,6 +100,18 @@ function Cursor:moveAndDraw(x_off, y_off)
self:draw()
end
function Cursor:moveTo(x_pos, y_pos)
self.x_pos = x_pos
self.y_pos = y_pos
end
function Cursor:moveToAndDraw(x_pos, y_pos)
self:clear()
self.x_pos = x_pos
self.y_pos = y_pos
self:draw()
end
function Cursor:moveHorizontalAndDraw(x_off)
self:clear()
self:move(x_off, 0)

@ -183,7 +183,7 @@ function UniReader:draworcache(no, preCache)
-- TODO: error handling
return nil
end
local dc = self:setzoom(page)
local dc = self:setzoom(page, preCache)
-- offset_x_in_page & offset_y_in_page is the offset within zoomed page
-- they are always positive.

Loading…
Cancel
Save