diff --git a/pdf_viewer/config.cpp b/pdf_viewer/config.cpp index 9c7ef4854..c9bbf23ab 100644 --- a/pdf_viewer/config.cpp +++ b/pdf_viewer/config.cpp @@ -80,7 +80,7 @@ extern bool FORCE_CUSTOM_LINE_ALGORITHM; extern float OVERVIEW_SIZE[2]; extern float OVERVIEW_OFFSET[2]; extern bool IGNORE_WHITESPACE_IN_PRESENTATION_MODE; -extern bool EXACT_HIGHLIGHT_SELECT; +extern bool LEGACY_WORD_SELECT; extern bool SHOW_DOC_PATH; extern float FASTREAD_OPACITY; extern bool SHOULD_WARN_ABOUT_USER_KEY_OVERRIDE; @@ -397,7 +397,7 @@ ConfigManager::ConfigManager(const Path& default_path, const Path& auto_path ,co configs.push_back({ L"overview_size", &OVERVIEW_SIZE, fvec2_serializer, fvec2_deserializer, nullptr }); configs.push_back({ L"overview_offset", &OVERVIEW_OFFSET, fvec2_serializer, fvec2_deserializer, nullptr }); configs.push_back({ L"ignore_whitespace_in_presentation_mode", &IGNORE_WHITESPACE_IN_PRESENTATION_MODE, bool_serializer, bool_deserializer, bool_validator }); - configs.push_back({ L"exact_highlight_select", &EXACT_HIGHLIGHT_SELECT, bool_serializer, bool_deserializer, bool_validator }); + configs.push_back({ L"legacy_word_select", &LEGACY_WORD_SELECT, bool_serializer, bool_deserializer, bool_validator }); configs.push_back({ L"show_doc_path", &SHOW_DOC_PATH, bool_serializer, bool_deserializer, bool_validator }); configs.push_back({ L"fastread_opacity", &FASTREAD_OPACITY, float_serializer, float_deserializer, nullptr }); configs.push_back({ L"should_warn_about_user_key_override", &SHOULD_WARN_ABOUT_USER_KEY_OVERRIDE, bool_serializer, bool_deserializer, bool_validator }); diff --git a/pdf_viewer/document.cpp b/pdf_viewer/document.cpp index 6e6182015..a4375728c 100644 --- a/pdf_viewer/document.cpp +++ b/pdf_viewer/document.cpp @@ -26,6 +26,7 @@ extern bool CREATE_TABLE_OF_CONTENTS_IF_NOT_EXISTS; extern int MAX_CREATED_TABLE_OF_CONTENTS_SIZE; extern bool FORCE_CUSTOM_LINE_ALGORITHM; extern bool SUPER_FAST_SEARCH; +extern bool LEGACY_WORD_SELECT; int Document::get_mark_index(char symbol) { @@ -80,7 +81,7 @@ void Document::fill_highlight_rects(fz_context* ctx, fz_document* doc_) { std::vector highlight_rects; std::vector merged_rects; std::wstring highlight_text; - get_text_selection(ctx, highlight.selection_begin, highlight.selection_end, true, highlight_rects, highlight_text, doc_); + get_text_selection(ctx, highlight.selection_begin, highlight.selection_end, LEGACY_WORD_SELECT, highlight_rects, highlight_text, doc_); merge_selected_character_rects(highlight_rects, merged_rects); if (i < highlights.size()) { @@ -1533,7 +1534,7 @@ void Document::embed_annotations(std::wstring new_file_path) { std::vector selected_characters_page_rects; std::wstring selected_text; - get_text_selection(highlight.selection_begin, highlight.selection_end, true, selected_characters, selected_text); + get_text_selection(highlight.selection_begin, highlight.selection_end, LEGACY_WORD_SELECT, selected_characters, selected_text); merge_selected_character_rects(selected_characters, merged_characters); for (auto absrect : merged_characters) { diff --git a/pdf_viewer/document_view.cpp b/pdf_viewer/document_view.cpp index afcb173b6..03c3f05ce 100644 --- a/pdf_viewer/document_view.cpp +++ b/pdf_viewer/document_view.cpp @@ -5,7 +5,6 @@ extern float MOVE_SCREEN_PERCENTAGE; extern float FIT_TO_PAGE_WIDTH_RATIO; extern float RULER_PADDING; extern float RULER_X_PADDING; -extern bool EXACT_HIGHLIGHT_SELECT; extern bool IGNORE_STATUSBAR_IN_PRESENTATION_MODE; @@ -199,6 +198,21 @@ void DocumentView::delete_closest_bookmark_to_offset(float offset) { current_document->delete_closest_bookmark(offset); } +void DocumentView::expand_highlight_with_index(int index) { + Highlight hl = get_highlight_with_index(index); + delete_highlight_with_index(index); + add_highlight(hl.selection_begin, hl.selection_end, true, hl.type); +} + +void DocumentView::expand_all_highlights() { + std::size_t num_highlights = current_document->get_highlights().size(); + if (num_highlights > 0) { + for (; num_highlights--;) { + expand_highlight_with_index(0); + } + } +} + float DocumentView::get_offset_x() { return offset_x; } @@ -298,17 +312,19 @@ void DocumentView::add_bookmark(std::wstring desc) { } } -void DocumentView::add_highlight(AbsoluteDocumentPos selection_begin, AbsoluteDocumentPos selection_end, char type) { +void DocumentView::add_highlight(AbsoluteDocumentPos selection_begin, AbsoluteDocumentPos selection_end, bool is_word_selection, char type) { if (current_document) { std::vector selected_characters; std::vector merged_characters; std::wstring selected_text; - get_text_selection(selection_begin, selection_end, !EXACT_HIGHLIGHT_SELECT, selected_characters, selected_text); + get_text_selection(selection_begin, selection_end, is_word_selection, selected_characters, selected_text); merge_selected_character_rects(selected_characters, merged_characters); if (selected_text.size() > 0) { - current_document->add_highlight(selected_text, merged_characters, selection_begin, selection_end, type); + const fz_point center_begin = rect_get_center(selected_characters.front()); + const fz_point center_end = rect_get_center(selected_characters.back()); + current_document->add_highlight(selected_text, merged_characters, { center_begin.x, center_begin.y }, { center_end.x, center_end.y }, type); } } } diff --git a/pdf_viewer/document_view.h b/pdf_viewer/document_view.h index ffe1c7701..f62783d76 100644 --- a/pdf_viewer/document_view.h +++ b/pdf_viewer/document_view.h @@ -78,6 +78,8 @@ class DocumentView { void delete_highlight_with_index(int index); void delete_highlight(Highlight hl); void delete_closest_bookmark_to_offset(float offset); + void expand_highlight_with_index(int index); + void expand_all_highlights(); float get_offset_x(); float get_offset_y(); AbsoluteDocumentPos get_offsets(); @@ -91,7 +93,7 @@ class DocumentView { void get_text_selection(AbsoluteDocumentPos selection_begin, AbsoluteDocumentPos selection_end, bool is_word_selection, std::vector& selected_characters, std::wstring& text_selection); void add_mark(char symbol); void add_bookmark(std::wstring desc); - void add_highlight(AbsoluteDocumentPos selection_begin, AbsoluteDocumentPos selection_end, char type); + void add_highlight(AbsoluteDocumentPos selection_begin, AbsoluteDocumentPos selection_end, bool is_word_selection, char type); void on_view_size_change(int new_width, int new_height); void absolute_to_window_pos(float absolute_x, float absolute_y, float* window_x, float* window_y); //void absolute_to_window_pos_pixels(float absolute_x, float absolute_y, float* window_x, float* window_y); diff --git a/pdf_viewer/input.cpp b/pdf_viewer/input.cpp index faaac2db1..28b91cb6c 100644 --- a/pdf_viewer/input.cpp +++ b/pdf_viewer/input.cpp @@ -628,6 +628,30 @@ class DeleteHighlightCommand : public Command { } }; +class ExpandHighlightCommand : public Command { + void perform(MainWidget* widget) { + if (widget->selected_highlight_index != -1) { + widget->main_document_view->expand_highlight_with_index(widget->selected_highlight_index); + } + widget->validate_render(); + } + + std::string get_name() { + return "expand_highlight"; + } +}; + +class ExpandAllHighlightsCommand : public Command { + void perform(MainWidget* widget) { + widget->main_document_view->expand_all_highlights(); + widget->validate_render(); + } + + std::string get_name() { + return "expand_all_highlights"; + } +}; + class GotoPortalCommand : public Command { void perform(MainWidget* widget) { std::optional link = widget->main_document_view->find_closest_portal(); @@ -1530,7 +1554,7 @@ class SetSelectHighlightTypeCommand : public SymbolCommand { class AddHighlightWithCurrentTypeCommand : public Command { void perform(MainWidget* widget) { if (widget->main_document_view->selected_character_rects.size() > 0) { - widget->main_document_view->add_highlight(widget->selection_begin, widget->selection_end, widget->select_highlight_type); + widget->main_document_view->add_highlight(widget->selection_begin, widget->selection_end, widget->is_word_selection, widget->select_highlight_type); widget->main_document_view->selected_character_rects.clear(); widget->selected_text.clear(); } @@ -2225,6 +2249,8 @@ CommandManager::CommandManager(ConfigManager* config_manager) { new_commands["delete_portal"] = []() {return std::make_unique< DeletePortalCommand>(); }; new_commands["delete_bookmark"] = []() {return std::make_unique< DeleteBookmarkCommand>(); }; new_commands["delete_highlight"] = []() {return std::make_unique< DeleteHighlightCommand>(); }; + new_commands["expand_highlight"] = []() {return std::make_unique< ExpandHighlightCommand>(); }; + new_commands["expand_all_highlights"] = []() {return std::make_unique< ExpandAllHighlightsCommand>(); }; new_commands["goto_link"] = []() {return std::make_unique< GotoPortalCommand>(); }; new_commands["goto_portal"] = []() {return std::make_unique< GotoPortalCommand>(); }; new_commands["edit_link"] = []() {return std::make_unique< EditPortalCommand>(); }; diff --git a/pdf_viewer/keys.config b/pdf_viewer/keys.config index 700767d4e..f0b97d816 100644 --- a/pdf_viewer/keys.config +++ b/pdf_viewer/keys.config @@ -184,6 +184,8 @@ goto_highlight gh goto_highlight_g gH # Left click on a highlight and then press the `delete_highlight` shortcut to delete it. delete_highlight dh +# Left click on a highlight and then press the `expand_highlight` shortcut to expand it to its word boundaries +expand_highlight eh # Sets the highlight type to be used for other operations (the default highlight type is 'a') #set_select_highlight_type diff --git a/pdf_viewer/main.cpp b/pdf_viewer/main.cpp index 61c4f4592..30ec6eca3 100644 --- a/pdf_viewer/main.cpp +++ b/pdf_viewer/main.cpp @@ -198,7 +198,6 @@ bool FORCE_CUSTOM_LINE_ALGORITHM = false; float OVERVIEW_SIZE[2] = { 0.8f, 0.4f }; float OVERVIEW_OFFSET[2] = { 0.0f, 0.0f }; bool IGNORE_WHITESPACE_IN_PRESENTATION_MODE = false; -bool EXACT_HIGHLIGHT_SELECT = false; bool SHOW_DOC_PATH = false; float FASTREAD_OPACITY = 0.5f; bool SHOULD_WARN_ABOUT_USER_KEY_OVERRIDE = true; @@ -215,6 +214,7 @@ float HYPERDRIVE_SPEED_FACTOR = 10.0f; float SMOOTH_SCROLL_SPEED = 3.0f; float SMOOTH_SCROLL_DRAG = 3000.0f; int PRERENDERED_PAGE_COUNT = 0; +bool LEGACY_WORD_SELECT = false; float PAGE_SEPARATOR_WIDTH = 0.0f; float PAGE_SEPARATOR_COLOR[3] = {0.9f, 0.9f, 0.9f}; diff --git a/pdf_viewer/main_widget.cpp b/pdf_viewer/main_widget.cpp index c22e31bc6..65ded5927 100644 --- a/pdf_viewer/main_widget.cpp +++ b/pdf_viewer/main_widget.cpp @@ -296,7 +296,7 @@ void MainWidget::mouseMoveEvent(QMouseEvent* mouse_event) { main_document_view->get_text_selection(selection_begin, selection_end, - is_word_selecting, + is_word_selection, main_document_view->selected_character_rects, selected_text); @@ -1409,7 +1409,7 @@ void MainWidget::handle_left_click(WindowPos click_pos, bool down, bool is_shift if (!mouse_drag_mode) { is_selecting = true; if (SINGLE_CLICK_SELECTS_WORDS) { - is_word_selecting = true; + is_word_selection = true; } } else { @@ -1438,10 +1438,9 @@ void MainWidget::handle_left_click(WindowPos click_pos, bool down, bool is_shift main_document_view->get_text_selection(last_mouse_down, abs_doc_pos, - is_word_selecting, + is_word_selection, main_document_view->selected_character_rects, selected_text); - is_word_selecting = false; } else { handle_click(click_pos); @@ -1657,7 +1656,7 @@ void MainWidget::mouseReleaseEvent(QMouseEvent* mevent) { else { handle_left_click({ mevent->pos().x(), mevent->pos().y() }, false, is_shift_pressed, is_control_pressed, is_alt_pressed); if (is_select_highlight_mode && (main_document_view->selected_character_rects.size() > 0)) { - main_document_view->add_highlight(selection_begin, selection_end, select_highlight_type); + main_document_view->add_highlight(selection_begin, selection_end, is_word_selection, select_highlight_type); clear_selected_text(); } if (main_document_view->selected_character_rects.size() > 0) { @@ -1703,10 +1702,10 @@ void MainWidget::mouseDoubleClickEvent(QMouseEvent* mevent) { if (mevent->button() == Qt::MouseButton::LeftButton) { is_selecting = true; if (SINGLE_CLICK_SELECTS_WORDS) { - is_word_selecting = false; + is_word_selection = false; } else { - is_word_selecting = true; + is_word_selection = true; } } } @@ -3678,14 +3677,14 @@ void MainWidget::handle_goto_bookmark_global() { void MainWidget::handle_add_highlight(char symbol) { if (main_document_view->selected_character_rects.size() > 0) { - main_document_view->add_highlight(selection_begin, selection_end, symbol); + main_document_view->add_highlight(selection_begin, selection_end, is_word_selection, symbol); main_document_view->selected_character_rects.clear(); selected_text.clear(); } else if (selected_highlight_index != -1) { Highlight new_highlight = main_document_view->get_highlight_with_index(selected_highlight_index); main_document_view->delete_highlight_with_index(selected_highlight_index); - main_document_view->add_highlight(new_highlight.selection_begin, new_highlight.selection_end, symbol); + main_document_view->add_highlight(new_highlight.selection_begin, new_highlight.selection_end, is_word_selection, symbol); selected_highlight_index = -1; } } diff --git a/pdf_viewer/main_widget.h b/pdf_viewer/main_widget.h index b4b0adff9..51bc65f9e 100644 --- a/pdf_viewer/main_widget.h +++ b/pdf_viewer/main_widget.h @@ -88,7 +88,7 @@ class MainWidget : public QWidget, ConfigFileChangeListener{ // is the user currently selecing text? (happens when we left click and move the cursor) bool is_selecting = false; // is the user in word select mode? (happens when we double left click and move the cursor) - bool is_word_selecting = false; + bool is_word_selection = false; std::wstring selected_text; bool is_select_highlight_mode = false; diff --git a/pdf_viewer/prefs.config b/pdf_viewer/prefs.config index 4bbfc0be3..30c41385a 100644 --- a/pdf_viewer/prefs.config +++ b/pdf_viewer/prefs.config @@ -3,6 +3,9 @@ # (can be 0 or 1) if set, shows a notification on startup if a new version of sioyek is available check_for_updates_on_startup 0 +# Force word selection mode for highlights read from database or when embedding into PDF files +legacy_word_select 0 + # Use old keybind parsing method (only for backwards compatibility) use_legacy_keybinds 0 diff --git a/pdf_viewer/utils.cpp b/pdf_viewer/utils.cpp index c53b3e404..f02dfdc1a 100644 --- a/pdf_viewer/utils.cpp +++ b/pdf_viewer/utils.cpp @@ -154,6 +154,10 @@ void rect_to_quad(fz_rect rect, float quad[8]) { quad[7] = rect.y1; } +fz_point rect_get_center(const fz_rect& rect) { + return { (rect.x0 + rect.x1) / 2, (rect.y0 + rect.y1) / 2 }; +} + void copy_to_clipboard(const std::wstring& text, bool selection) { auto clipboard = QGuiApplication::clipboard(); auto qtext = QString::fromStdWString(text); @@ -600,7 +604,8 @@ fz_stext_char* find_closest_char_to_document_point(const std::vectororigin; + // This works better than current_char->origin + const fz_point quad_center = rect_get_center(fz_rect_from_quad(current_char->quad)); float distance = dist_squared(document_point, quad_center); if (distance < min_distance) { min_distance = distance; diff --git a/pdf_viewer/utils.h b/pdf_viewer/utils.h index 10873c6c4..ed3a9c9f9 100644 --- a/pdf_viewer/utils.h +++ b/pdf_viewer/utils.h @@ -73,6 +73,7 @@ int argminf(const std::vector &collection, std::function f) { return min_index; } void rect_to_quad(fz_rect rect, float quad[8]); +fz_point rect_get_center(const fz_rect& rect); void copy_to_clipboard(const std::wstring& text, bool selection=false); void install_app(const char* argv0); int get_f_key(std::wstring name); diff --git a/resources/sioyek.1 b/resources/sioyek.1 index 1ad3a2d1e..ec25d1334 100644 --- a/resources/sioyek.1 +++ b/resources/sioyek.1 @@ -1263,12 +1263,6 @@ Offset of the overview window as floats from the center of the page. Always use fit_to_page_smart (ignoring whitespace) in presentation view. .HP -.B exact_highlight_select -.I boolean - -If set to 0, then in word select mode, select the whole word even if -the cursor is only partially on the word. If set to 1, then select the word only if the range of the cursor's selection fully includes the word. -.HP .B show_doc_path .I boolean @@ -1312,6 +1306,12 @@ always attempted. If set to 0, search is performed by the mupdf backend. If set to 1, a super fast search index is used instead. This leads to a slight increase in memory. .HP +.B legacy_word_select +.I boolean + +If set to 1, highlights are expanded to entail entire words when read from the +database or when embedded into PDF files. +.HP .B case_sensitive_search .I boolean