From 637904a711421ec38d4da6a9a16647cc6f0145ca Mon Sep 17 00:00:00 2001 From: chrox Date: Sat, 18 Jan 2014 03:05:17 +0800 Subject: [PATCH] add text highlight for credocument Three highlight drawers "lighten", "underscore" and "invert" are available in reader menu. This should implement #176. --- frontend/document/credocument.lua | 35 +++++- frontend/ui/gesturedetector.lua | 2 +- frontend/ui/reader/readerhighlight.lua | 153 +++++++++++++++++++------ frontend/ui/reader/readerview.lua | 35 +++++- frontend/ui/readerui.lua | 18 +-- koreader-base | 2 +- 6 files changed, 191 insertions(+), 54 deletions(-) diff --git a/frontend/document/credocument.lua b/frontend/document/credocument.lua index f7173c1f9..b6bd76fff 100644 --- a/frontend/document/credocument.lua +++ b/frontend/document/credocument.lua @@ -2,6 +2,7 @@ local Geom = require("ui/geometry") local CreOptions = require("ui/data/creoptions") local Document = require("document/document") local Configurable = require("ui/reader/configurable") +local Geom = require("ui/geometry") local Font = require("ui/font") local Device = require("ui/device") local Screen = require("ui/screen") @@ -133,12 +134,12 @@ function CreDocument:getPageCount() end function CreDocument:getWordFromPosition(pos) - local word_box = self._document:getWordFromPos(pos.x, pos.y) + local word_box = self._document:getWordFromPosition(pos.x, pos.y) if word_box.word then return { word = word_box.word, page = self._document:getCurrentPage(), - sbox = { + sbox = Geom:new{ x = word_box.x0, y = word_box.y0, w = word_box.x1 - word_box.x0, h = word_box.y1 - word_box.y0, @@ -147,8 +148,34 @@ function CreDocument:getWordFromPosition(pos) end end -function CreDocument:getTextFromPositions(doc, pos0, pos1) - DEBUG("getTextFromPositions not finished yet") +function CreDocument:getTextFromPositions(pos0, pos1) + local text_range = self._document:getTextFromPositions(pos0.x, pos0.y, pos1.x, pos1.y) + DEBUG("CreDocument: get text range", text_range) + local line_boxes = self:getScreenBoxesFromPositions(text_range.pos0, text_range.pos1) + return { + text = text_range.text, + pos0 = text_range.pos0, + pos1 = text_range.pos1, + sboxes = line_boxes, -- boxes on screen + } +end + +function CreDocument:getScreenBoxesFromPositions(pos0, pos1) + local line_boxes = {} + if pos0 and pos1 then + local word_boxes = self._document:getWordBoxesFromPositions(pos0, pos1) + --DEBUG("word boxes", word_boxes) + for i = 1, #word_boxes do + local line_box = word_boxes[i] + table.insert(line_boxes, Geom:new{ + x = line_box.x0, y = line_box.y0, + w = line_box.x1 - line_box.x0, + h = line_box.y1 - line_box.y0, + }) + end + --DEBUG("line boxes", line_boxes) + end + return line_boxes end function CreDocument:drawCurrentView(target, x, y, rect, pos) diff --git a/frontend/ui/gesturedetector.lua b/frontend/ui/gesturedetector.lua index a299b6181..ae265ba85 100644 --- a/frontend/ui/gesturedetector.lua +++ b/frontend/ui/gesturedetector.lua @@ -81,7 +81,7 @@ function GestureDetector:feedEvent(tevs) repeat local tev = table.remove(tevs) if tev then - DEBUG("tev fed|",tev.timev.sec,"|",tev.timev.usec,"|",tev.x,"|",tev.y,"|",tev.id,"| Evt",tev.slot) + --DEBUG("tev fed|",tev.timev.sec,"|",tev.timev.usec,"|",tev.x,"|",tev.y,"|",tev.id,"| Evt",tev.slot) local slot = tev.slot if not self.states[slot] then self:clearState(slot) -- initiate state diff --git a/frontend/ui/reader/readerhighlight.lua b/frontend/ui/reader/readerhighlight.lua index eea149ae9..fc3a7498a 100644 --- a/frontend/ui/reader/readerhighlight.lua +++ b/frontend/ui/reader/readerhighlight.lua @@ -68,6 +68,7 @@ function ReaderHighlight:init() doc = _("highlight text") }, } end + self.ui.menu:registerToMainMenu(self) end function ReaderHighlight:initGesListener() @@ -116,6 +117,39 @@ function ReaderHighlight:initGesListener() } end +function ReaderHighlight:addToMainMenu(tab_item_table) + -- insert table to main reader menu + table.insert(tab_item_table.typeset, { + text_func = function() + return _("Set highlight drawer ").."( "..self.view.highlight.saved_drawer.." )" + end, + sub_item_table = self:genHighlightDrawerMenu(), + }) +end + +function ReaderHighlight:genHighlightDrawerMenu() + return { + { + text = _("Lighten"), + callback = function() + self.view.highlight.saved_drawer = "lighten" + end + }, + { + text = _("Underscore"), + callback = function() + self.view.highlight.saved_drawer = "underscore" + end + }, + { + text = _("Invert"), + callback = function() + self.view.highlight.saved_drawer = "invert" + end + }, + } +end + function ReaderHighlight:onSetDimensions(dimen) -- update listening according to new screen dimen if Device:isTouchDevice() then @@ -124,24 +158,33 @@ function ReaderHighlight:onSetDimensions(dimen) end function ReaderHighlight:onTap(arg, ges) - local function inside_box(ges, box) - local pos = self.view:screenToPageTransform(ges.pos) - if pos then - local x, y = pos.x, pos.y - if box.x <= x and box.y <= y - and box.x + box.w >= x - and box.y + box.h >= y then - return true - end - end - end if self.hold_pos then self.view.highlight.temp[self.hold_pos.page] = nil UIManager:setDirty(self.dialog, "partial") self.hold_pos = nil return true end + if self.ui.document.info.has_pages then + return self:onTapPageSavedHighlight(ges) + else + return self:onTapXPointerSavedHighlight(ges) + end +end + +local function inside_box(pos, box) + if pos then + local x, y = pos.x, pos.y + if box.x <= x and box.y <= y + and box.x + box.w >= x + and box.y + box.h >= y then + return true + end + end +end + +function ReaderHighlight:onTapPageSavedHighlight(ges) local pages = self.view:getCurrentPageList() + local pos = self.view:screenToPageTransform(ges.pos) for key, page in pairs(pages) do local items = self.view.highlight.saved[page] if not items then items = {} end @@ -150,31 +193,29 @@ function ReaderHighlight:onTap(arg, ges) local boxes = self.ui.document:getPageBoxesFromPositions(page, pos0, pos1) if boxes then for index, box in pairs(boxes) do - if inside_box(ges, box) then + if inside_box(pos, box) then + DEBUG("Tap on hightlight") + return self:onShowHighlightDialog(page, i) + end + end + end + end + end +end + +function ReaderHighlight:onTapXPointerSavedHighlight(ges) + local pos = self.view:screenToPageTransform(ges.pos) + for page, _ in pairs(self.view.highlight.saved) do + local items = self.view.highlight.saved[page] + if not items then items = {} end + for i = 1, #items do + local pos0, pos1 = items[i].pos0, items[i].pos1 + local boxes = self.ui.document:getScreenBoxesFromPositions(pos0, pos1) + if boxes then + for index, box in pairs(boxes) do + if inside_box(pos, box) then DEBUG("Tap on hightlight") - self.edit_highlight_dialog = HighlightDialog:new{ - buttons = { - { - { - text = _("Delete"), - callback = function() - self:deleteHighlight(page, i) - UIManager:close(self.edit_highlight_dialog) - end, - }, - { - text = _("Edit"), - enabled = false, - callback = function() - self:editHighlight() - UIManager:close(self.edit_highlight_dialog) - end, - }, - }, - }, - } - UIManager:show(self.edit_highlight_dialog) - return true + return self:onShowHighlightDialog(page, i) end end end @@ -182,6 +223,32 @@ function ReaderHighlight:onTap(arg, ges) end end +function ReaderHighlight:onShowHighlightDialog(page, index) + self.edit_highlight_dialog = HighlightDialog:new{ + buttons = { + { + { + text = _("Delete"), + callback = function() + self:deleteHighlight(page, index) + UIManager:close(self.edit_highlight_dialog) + end, + }, + { + text = _("Edit"), + enabled = false, + callback = function() + self:editHighlight() + UIManager:close(self.edit_highlight_dialog) + end, + }, + }, + }, + } + UIManager:show(self.edit_highlight_dialog) + return true +end + function ReaderHighlight:onHold(arg, ges) self.hold_pos = self.view:screenToPageTransform(ges.pos) DEBUG("hold position in page", self.hold_pos) @@ -213,13 +280,14 @@ function ReaderHighlight:onHoldPan(arg, ges) if self.selected_text then self.view.highlight.temp[self.hold_pos.page] = self.selected_text.sboxes -- remove selected word if hold moves out of word box - if self.selected_word and - not self.selected_word.sbox:contains(self.selected_text.sboxes[1]) or + if not self.selected_text.sboxes or #self.selected_text.sboxes == 0 then + self.selected_word = nil + elseif self.selected_word and not self.selected_word.sbox:contains(self.selected_text.sboxes[1]) or #self.selected_text.sboxes > 1 then self.selected_word = nil end - UIManager:setDirty(self.dialog, "partial") end + UIManager:setDirty(self.dialog, "partial") end function ReaderHighlight:lookup(selected_word) @@ -324,6 +392,7 @@ function ReaderHighlight:saveHighlight() hl_item["pos0"] = self.selected_text.pos0 hl_item["pos1"] = self.selected_text.pos1 hl_item["datetime"] = os.date("%Y-%m-%d %H:%M:%S") + hl_item["drawer"] = self.view.highlight.saved_drawer table.insert(self.view.highlight.saved[page], hl_item) if self.selected_text.text ~= "" then self:exportToClippings(page, hl_item) @@ -369,4 +438,12 @@ function ReaderHighlight:editHighlight() DEBUG("edit highlight") end +function ReaderHighlight:onReadSettings(config) + self.view.highlight.saved_drawer = config:readSetting("highlight_drawer") or self.view.highlight.saved_drawer +end + +function ReaderHighlight:onSaveSettings() + self.ui.doc_settings:saveSetting("highlight_drawer", self.view.highlight.saved_drawer) +end + return ReaderHighlight diff --git a/frontend/ui/reader/readerview.lua b/frontend/ui/reader/readerview.lua index a7f58bee1..23865f2b6 100644 --- a/frontend/ui/reader/readerview.lua +++ b/frontend/ui/reader/readerview.lua @@ -22,7 +22,7 @@ local ReaderView = OverlapGroup:new{ bbox = nil, }, outer_page_color = DOUTER_PAGE_COLOR, - -- hightlight + -- hightlight with "lighten" or "underscore" or "invert" highlight = { lighten_color = 0.2, -- color range [0.0, 1.0] temp_drawer = "invert", @@ -345,18 +345,27 @@ function ReaderView:drawTempHighlight(bb, x, y) end function ReaderView:drawSavedHighlight(bb, x, y) + if self.ui.document.info.has_pages then + self:drawPageSavedHighlight(bb, x, y) + else + self:drawXPointerSavedHighlight(bb, x, y) + end +end + +function ReaderView:drawPageSavedHighlight(bb, x, y) local pages = self:getCurrentPageList() for _, page in pairs(pages) do local items = self.highlight.saved[page] if not items then items = {} end for i = 1, #items do - local pos0, pos1 = items[i].pos0, items[i].pos1 + local item = items[i] + local pos0, pos1 = item.pos0, item.pos1 local boxes = self.ui.document:getPageBoxesFromPositions(page, pos0, pos1) if boxes then for _, box in pairs(boxes) do local rect = self:pageToScreenTransform(page, box) if rect then - self:drawHighlightRect(bb, x, y, rect, self.highlight.saved_drawer) + self:drawHighlightRect(bb, x, y, rect, item.drawer or self.highlight.saved_drawer) end end -- end for each box end -- end if boxes @@ -364,6 +373,26 @@ function ReaderView:drawSavedHighlight(bb, x, y) end -- end for each page end +function ReaderView:drawXPointerSavedHighlight(bb, x, y) + for page, _ in pairs(self.highlight.saved) do + local items = self.highlight.saved[page] + if not items then items = {} end + for j = 1, #items do + local item = items[j] + local pos0, pos1 = item.pos0, item.pos1 + local boxes = self.ui.document:getScreenBoxesFromPositions(pos0, pos1) + if boxes then + for _, box in pairs(boxes) do + local rect = self:pageToScreenTransform(page, box) + if rect then + self:drawHighlightRect(bb, x, y, rect, item.drawer or self.highlight.saved_drawer) + end + end -- end for each box + end -- end if boxes + end -- end for each hightlight + end -- end for all saved highlight +end + function ReaderView:drawHighlightRect(bb, x, y, rect, drawer) local x, y, w, h = rect.x, rect.y, rect.w, rect.h diff --git a/frontend/ui/readerui.lua b/frontend/ui/readerui.lua index 3ddeac0cf..fb811d29a 100644 --- a/frontend/ui/readerui.lua +++ b/frontend/ui/readerui.lua @@ -83,6 +83,12 @@ function ReaderUI:init() ui = self, document = self.document, } + -- reader menu controller + -- hold reference to menu widget + self.menu = ReaderMenu:new{ + view = self[1], + ui = self + } -- link table.insert(self, ReaderLink:new{ dialog = self.dialog, @@ -97,25 +103,23 @@ function ReaderUI:init() ui = self, document = self.document, }) + -- menu widget should be registered after link widget and highlight widget + -- so that taps on link and highlight areas won't popup reader menu + table.insert(self, self.menu) -- rotation controller table.insert(self, ReaderRotation:new{ dialog = self.dialog, view = self[1], ui = self }) - -- reader menu controller - self.menu = ReaderMenu:new{ - view = self[1], - ui = self - } - table.insert(self, self.menu) -- hold reference to menu widget -- Table of content controller + -- hold reference to bm widget self.toc = ReaderToc:new{ dialog = self.dialog, view = self[1], ui = self } - table.insert(self, self.toc) -- hold reference to bm widget + table.insert(self, self.toc) -- bookmark controller table.insert(self, ReaderBookmark:new{ dialog = self.dialog, diff --git a/koreader-base b/koreader-base index 6284768bc..e601d7996 160000 --- a/koreader-base +++ b/koreader-base @@ -1 +1 @@ -Subproject commit 6284768bc3e317385164e9955837ac75265ffd1d +Subproject commit e601d7996ae44eb84ad070369993263c46ba3532