From 3d40def5061f1129c016a8591d067c4a00343e28 Mon Sep 17 00:00:00 2001 From: luhuaei Date: Sun, 9 Feb 2020 14:51:40 +0800 Subject: [PATCH 1/3] pdf-viewer: add multi annot type for select text. --- app/pdf-viewer/buffer.py | 36 +++++++++++++++++++++++++++++++----- eaf.el | 5 ++++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/app/pdf-viewer/buffer.py b/app/pdf-viewer/buffer.py index 2932b96..1893004 100755 --- a/app/pdf-viewer/buffer.py +++ b/app/pdf-viewer/buffer.py @@ -166,8 +166,19 @@ class AppBuffer(Buffer): def add_annot_highlight(self): if self.buffer_widget.is_select_mode: - self.buffer_widget.highlight_select_char_area() - self.buffer_widget.cleanup_select() + self.buffer_widget.annot_select_char_area("highlight") + + def add_annot_strikeout(self): + if self.buffer_widget.is_select_mode: + self.buffer_widget.annot_select_char_area("strikeout") + + def add_annot_underline(self): + if self.buffer_widget.is_select_mode: + self.buffer_widget.annot_select_char_area("underline") + + def add_annot_squiggly(self): + if self.buffer_widget.is_select_mode: + self.buffer_widget.annot_select_char_area("squiggly") class PdfViewerWidget(QWidget): translate_double_click_word = QtCore.pyqtSignal(str) @@ -219,6 +230,8 @@ class PdfViewerWidget(QWidget): self.select_area_annot_cache_dict = {} self.char_dict = {k:None for k in range(self.page_total_number)} + # annot list + self.select_area_annot_quad_cache_dict = {} # Init scroll attributes. self.scroll_step = 20 self.scroll_offset = 0 @@ -746,9 +759,21 @@ class PdfViewerWidget(QWidget): string += "\n\n" # add new line on page end. return string - def highlight_select_char_area(self): - for key in self.select_area_annot_cache_dict.keys(): - self.select_area_annot_cache_dict[key] = None + def annot_select_char_area(self, annot_type="highlight"): + self.cleanup_select() # needs first cleanup select highlight mark. + for page_index, quad_list in self.select_area_annot_quad_cache_dict.items(): + page = self.document[page_index] + + if annot_type == "highlight": + new_annot = page.addHighlightAnnot(quad_list) + elif annot_type == "strikeout": + new_annot = page.addStrikeoutAnnot(quad_list) + elif annot_type == "underline": + new_annot = page.addUnderlineAnnot(quad_list) + elif annot_type == "squiggly": + new_annot = page.addSquigglyAnnot(quad_list) + + new_annot.parent = page self.document.saveIncr() def cleanup_select(self): @@ -797,6 +822,7 @@ class PdfViewerWidget(QWidget): # refresh annot self.select_area_annot_cache_dict[page_index] = annot + self.select_area_annot_quad_cache_dict[page_index] = quad_list self.page_cache_pixmap_dict.clear() self.update() diff --git a/eaf.el b/eaf.el index 3934f53..08905b8 100644 --- a/eaf.el +++ b/eaf.el @@ -314,7 +314,10 @@ Try not to modify this alist directly. Use `eaf-setq' to modify instead." ("M-w" . "copy_select") ("C-s" . "search_text_forward") ("C-r" . "search_text_backward") - ("h" . "add_annot_highlight")) + ("h" . "add_annot_highlight") + ("u" . "add_annot_underline") + ("s" . "add_annot_squiggly") + ("d" . "add_annot_strikeout")) "The keybinding of EAF PDF Viewer." :type 'cons) From 01a55a8f3bfb5de08eee8573aaeed3d38dc0690f Mon Sep 17 00:00:00 2001 From: luhuaei Date: Sun, 9 Feb 2020 16:02:53 +0800 Subject: [PATCH 2/3] pdf-viewer: refactor jump link code. --- app/pdf-viewer/buffer.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/app/pdf-viewer/buffer.py b/app/pdf-viewer/buffer.py index 1893004..b10c7f8 100755 --- a/app/pdf-viewer/buffer.py +++ b/app/pdf-viewer/buffer.py @@ -138,7 +138,7 @@ class AppBuffer(Buffer): def action_quit(self): if self.buffer_widget.is_mark_search: self.buffer_widget.cleanup_search() - if self.buffer_widget.is_mark_link: + if self.buffer_widget.is_jump_link: self.buffer_widget.cleanup_links() if self.buffer_widget.is_select_mode: self.buffer_widget.cleanup_select() @@ -213,6 +213,7 @@ class PdfViewerWidget(QWidget): self.mark_link_annot_cache_dict = {} #jump link + self.is_jump_link = False self.jump_link_key_cache_dict = {} self.jump_link_annot_cache_dict = {} @@ -304,11 +305,9 @@ class PdfViewerWidget(QWidget): self.page_cache_scale = scale self.page_cache_trans = fitz.Matrix(scale, scale) + page = self.document[index] if self.is_mark_link: page = self.add_mark_link(index) - else: - self.delete_all_mark_link() - page = self.document[index] # follow page search text if self.is_mark_search: @@ -537,8 +536,12 @@ class PdfViewerWidget(QWidget): # Re-render page. self.update() - def toggle_mark_link(self): - self.is_mark_link = not self.is_mark_link + def toggle_mark_link(self): # mark_link will add underline mark on link, using prompt link position. + if self.is_mark_link: + self.cleanup_mark_link() + else: + self.is_mark_link = True + self.page_cache_pixmap_dict.clear() self.update() @@ -553,14 +556,14 @@ class PdfViewerWidget(QWidget): self.mark_link_annot_cache_dict[index] = annot_list return page - def delete_all_mark_link(self): - if (not self.is_mark_link) and self.mark_link_annot_cache_dict: + def cleanup_mark_link(self): + if self.mark_link_annot_cache_dict: for index in self.mark_link_annot_cache_dict.keys(): page = self.document[index] for annot in self.mark_link_annot_cache_dict[index]: page.deleteAnnot(annot) + self.is_mark_link = False self.mark_link_annot_cache_dict.clear() - self.update() def generate_random_key(self, count): letters = "ASDFHJKLQWEIOP" @@ -611,6 +614,7 @@ class PdfViewerWidget(QWidget): self.jump_link_annot_cache_dict.clear() def jump_to_link(self, key): + self.is_jump_link = True key = str(key).upper() if key in self.jump_link_key_cache_dict: link = self.jump_link_key_cache_dict[key] @@ -621,7 +625,7 @@ class PdfViewerWidget(QWidget): self.message_to_emacs.emit("Landed on Page " + str(link["page"] + 1)) def cleanup_links(self): - self.is_mark_link = False + self.is_jump_link = False self.delete_all_mark_jump_link_tips() self.page_cache_pixmap_dict.clear() From ddec12eaf2a942f83d188641057a24ae7e69a21c Mon Sep 17 00:00:00 2001 From: luhuaei Date: Sun, 9 Feb 2020 21:12:28 +0800 Subject: [PATCH 3/3] pdf-viewer: support delete annot. --- app/pdf-viewer/buffer.py | 78 ++++++++++++++++++++++++++++++---------- eaf.el | 2 +- 2 files changed, 61 insertions(+), 19 deletions(-) diff --git a/app/pdf-viewer/buffer.py b/app/pdf-viewer/buffer.py index b10c7f8..f73ebe4 100755 --- a/app/pdf-viewer/buffer.py +++ b/app/pdf-viewer/buffer.py @@ -21,7 +21,7 @@ from PyQt5 import QtCore from PyQt5.QtCore import Qt, QRect, QEvent -from PyQt5.QtGui import QColor, QPixmap, QImage, QFont +from PyQt5.QtGui import QColor, QPixmap, QImage, QFont, QCursor from PyQt5.QtGui import QPainter from PyQt5.QtWidgets import QWidget from core.buffer import Buffer @@ -168,9 +168,11 @@ class AppBuffer(Buffer): if self.buffer_widget.is_select_mode: self.buffer_widget.annot_select_char_area("highlight") - def add_annot_strikeout(self): + def add_annot_strikeout_or_delete_annot(self): if self.buffer_widget.is_select_mode: self.buffer_widget.annot_select_char_area("strikeout") + elif self.buffer_widget.is_hover_annot: + self.buffer_widget.annot_handler("delete") def add_annot_underline(self): if self.buffer_widget.is_select_mode: @@ -229,10 +231,12 @@ class PdfViewerWidget(QWidget): self.last_char_rect_index = None self.last_char_page_index = None self.select_area_annot_cache_dict = {} + self.select_area_annot_quad_cache_dict = {} self.char_dict = {k:None for k in range(self.page_total_number)} - # annot list - self.select_area_annot_quad_cache_dict = {} + # annot + self.is_hover_annot = False + # Init scroll attributes. self.scroll_step = 20 self.scroll_offset = 0 @@ -714,9 +718,9 @@ class PdfViewerWidget(QWidget): return chars_list - def get_char_rect_index(self, event): + def get_char_rect_index(self): offset = 15 - ex, ey, page_index = self.get_event_absolute_position(event) + ex, ey, page_index = self.get_cursor_absolute_position() if ex and ey and page_index: rect = fitz.Rect(ex, ey, ex + offset, ey + offset) for char_index, char in enumerate(self.char_dict[page_index]): @@ -779,6 +783,7 @@ class PdfViewerWidget(QWidget): new_annot.parent = page self.document.saveIncr() + self.select_area_annot_quad_cache_dict.clear() def cleanup_select(self): self.is_select_mode = False @@ -843,6 +848,40 @@ class PdfViewerWidget(QWidget): self.start_char_page_index = None self.start_char_rect_index = None + def hover_annot(self): + ex, ey, page_index = self.get_cursor_absolute_position() + page = self.document[page_index] + annots = page.annots() + if not annots: + return None + + annot = None # annots is generator, will probably cause annot don't assign + for annot in annots: + if annot.rect.contains(fitz.Point(ex, ey)): + self.is_hover_annot = True + annot.setOpacity(0.5) + self.message_to_emacs.emit("[d]Delete Annot") + else: + annot.setOpacity(1) # restore annot + self.is_hover_annot = False + annot.update() + + self.page_cache_pixmap_dict.clear() + self.update() + return page, annot + + def annot_handler(self, action=None): + + page, annot = self.hover_annot() + + if annot.parent: + if action == "delete": + page.deleteAnnot(annot) + + self.document.saveIncr() + self.page_cache_pixmap_dict.clear() + self.update() + def jump_to_page(self, page_num): self.update_scroll_offset(min(max(self.scale * (int(page_num) - 1) * self.page_height, 0), self.max_scroll_offset())) @@ -854,10 +893,10 @@ class PdfViewerWidget(QWidget): self.scroll_offset = new_offset self.update() - def get_event_absolute_position(self, event): + def get_cursor_absolute_position(self): start_page_index = self.get_start_page_index() last_page_index = self.get_last_page_index() - pos = event.pos() + ex, ey = QCursor.pos().x(), QCursor.pos().y() for index in list(range(start_page_index, last_page_index)): if index < self.page_total_number: @@ -865,21 +904,21 @@ class PdfViewerWidget(QWidget): render_x = int((self.rect().width() - render_width) / 2) # computer absolute coordinate of page - x = (pos.x() - render_x) * 1.0 / self.scale - if pos.y() + self.scroll_offset < (start_page_index + 1) * self.scale * self.page_height: + x = (ex - render_x) * 1.0 / self.scale + if ey + self.scroll_offset < (start_page_index + 1) * self.scale * self.page_height: page_offset = self.scroll_offset - start_page_index * self.scale * self.page_height page_index = index else: # if display two pages, pos.y() will add page_padding page_offset = self.scroll_offset - (start_page_index + 1) * self.scale * self.page_height - self.page_padding page_index = index + 1 - y = (pos.y() + page_offset) * 1.0 / self.scale + y = (ey + page_offset) * 1.0 / self.scale return x, y, page_index return None, None, None - def get_event_link(self, event): - ex, ey, page_index = self.get_event_absolute_position(event) + def get_event_link(self): + ex, ey, page_index = self.get_cursor_absolute_position() if page_index is None: return None @@ -892,8 +931,8 @@ class PdfViewerWidget(QWidget): return None - def get_double_click_word(self, event): - ex, ey, page_index = self.get_event_absolute_position(event) + def get_double_click_word(self): + ex, ey, page_index = self.get_cursor_absolute_position() if page_index is None: return None page = self.document[page_index] @@ -909,17 +948,20 @@ class PdfViewerWidget(QWidget): def eventFilter(self, obj, event): if event.type() == QEvent.MouseMove: if self.is_select_mode: - rect_index, page_index = self.get_char_rect_index(event) + rect_index, page_index = self.get_char_rect_index() if rect_index and page_index: if self.start_char_rect_index is None or self.start_char_page_index is None: self.start_char_rect_index, self.start_char_page_index = rect_index, page_index else: self.last_char_rect_index, self.last_char_page_index = rect_index, page_index self.mark_select_char_area() + else: + self.hover_annot() + elif event.type() == QEvent.MouseButtonPress: if event.button() == Qt.LeftButton: - event_link = self.get_event_link(event) + event_link = self.get_event_link() if event_link: self.jump_to_page(event_link["page"] + 1) @@ -927,7 +969,7 @@ class PdfViewerWidget(QWidget): if self.is_mark_search: self.cleanup_search() if event.button() == Qt.RightButton: - double_click_word = self.get_double_click_word(event) + double_click_word = self.get_double_click_word() if double_click_word: self.translate_double_click_word.emit(double_click_word) elif event.button() == Qt.LeftButton: diff --git a/eaf.el b/eaf.el index 08905b8..5c2e3e3 100644 --- a/eaf.el +++ b/eaf.el @@ -317,7 +317,7 @@ Try not to modify this alist directly. Use `eaf-setq' to modify instead." ("h" . "add_annot_highlight") ("u" . "add_annot_underline") ("s" . "add_annot_squiggly") - ("d" . "add_annot_strikeout")) + ("d" . "add_annot_strikeout_or_delete_annot")) "The keybinding of EAF PDF Viewer." :type 'cons)