Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pdf_viewer/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ int SINGLE_MAIN_WINDOW_MOVE[2] = { -1, -1 };
bool ENABLE_EXPERIMENTAL_FEATURES = false;
bool CREATE_TABLE_OF_CONTENTS_IF_NOT_EXISTS = true;
int MAX_CREATED_TABLE_OF_CONTENTS_SIZE = 5000;
int TOC_SCROLL_MARGIN = 3;
bool FORCE_CUSTOM_LINE_ALGORITHM = false;
float OVERVIEW_SIZE[2] = { 0.8f, 0.4f };
float OVERVIEW_OFFSET[2] = { 0.0f, 0.0f };
Expand Down Expand Up @@ -1130,6 +1131,7 @@ ConfigManager::ConfigManager(const Path& default_path, const Path& auto_path, co
add_int(L"status_bar_font_size", &STATUS_BAR_FONT_SIZE, IntExtras{1, 100});
add_int(L"text_summary_context_size", &TEXT_SUMMARY_CONTEXT_SIZE, IntExtras{1, 100});
add_int(L"max_created_toc_size", &MAX_CREATED_TABLE_OF_CONTENTS_SIZE, IntExtras{1, 100000});
add_int(L"toc_scroll_margin", &TOC_SCROLL_MARGIN, IntExtras{0, 100});
add_int(L"prerendered_page_count", &PRERENDERED_PAGE_COUNT, IntExtras{0, 10});
add_int(L"reload_interval_miliseconds", &RELOAD_INTERVAL_MILISECONDS, IntExtras{0, 10000});
add_ivec2(L"main_window_size", MAIN_WINDOW_SIZE);
Expand Down
5 changes: 5 additions & 0 deletions pdf_viewer/prefs.config
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ create_table_of_contents_if_not_exists 1
# Limits the maximum size of created table of contents
max_created_toc_size 5000

# Number of rows of context to keep visible above/below the current selection
# when navigating the table of contents with the keyboard. Set to 0 to restore
# the old behavior (scroll the bare minimum needed to keep the selection visible).
toc_scroll_margin 3

# Warn the user on the command line only when redefining keys inside
# the same file. When set to 1, sioyek will warn when redefining keys
# from other files also
Expand Down
48 changes: 47 additions & 1 deletion pdf_viewer/ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ const int max_select_size = 100;
extern bool SMALL_TOC;
extern bool MULTILINE_MENUS;
extern bool TOUCH_MODE;
extern int TOC_SCROLL_MARGIN;


class HierarchialSortFilterProxyModel : public QSortFilterProxyModel {
Expand Down Expand Up @@ -173,6 +174,51 @@ class BaseSelectorWidget : public QWidget {

};

// QTreeView (and QAbstractItemView in general) only scrolls the bare minimum
// needed to bring the current row into view (ScrollHint::EnsureVisible with no
// margin). That means keyboard navigation can push the selection all the way to
// the last visible row with no look-ahead, and when reversing direction the
// viewport doesn't budge until the selection reaches the edge of whatever is
// already on screen.
//
// This subclass keeps exactly `TOC_SCROLL_MARGIN` rows of context visible
// above/below the current row at all times, by additionally requesting
// visibility for an index that many steps above/below the target before
// scrolling to the target itself. Because this re-asserts the same fixed
// margin on every single step, continuous movement toward an edge ends up
// scrolling the view exactly one row per keypress -- the selection stays
// pinned at a fixed screen offset while the list moves underneath it. The
// margin size itself never varies, unlike a recentering/chunked approach.
class SioyekTreeView : public QTreeView {
public:
using QTreeView::QTreeView;

protected:
QModelIndex step_index(const QModelIndex& from, int n, bool down) const {
QModelIndex cur = from;
for (int i = 0; i < n; i++) {
QModelIndex next = down ? indexBelow(cur) : indexAbove(cur);
if (!next.isValid()) break;
cur = next;
}
return cur;
}

void scrollTo(const QModelIndex& index, ScrollHint hint = EnsureVisible) override {
if (!index.isValid() || TOC_SCROLL_MARGIN <= 0) {
QTreeView::scrollTo(index, hint);
return;
}

QModelIndex above = step_index(index, TOC_SCROLL_MARGIN, false);
QModelIndex below = step_index(index, TOC_SCROLL_MARGIN, true);

QTreeView::scrollTo(below, EnsureVisible);
QTreeView::scrollTo(above, EnsureVisible);
QTreeView::scrollTo(index, hint);
}
};

template<typename T>
class FilteredTreeSelect : public BaseSelectorWidget {
private:
Expand All @@ -189,7 +235,7 @@ class FilteredTreeSelect : public BaseSelectorWidget {
FilteredTreeSelect(bool fuzzy, QStandardItemModel* item_model,
std::function<void(const std::vector<int>&)> on_done,
MainWidget* parent,
std::vector<int> selected_index) : BaseSelectorWidget(new QTreeView(), fuzzy, item_model, parent),
std::vector<int> selected_index) : BaseSelectorWidget(new SioyekTreeView(), fuzzy, item_model, parent),
on_done(on_done)
{
auto index = QModelIndex();
Expand Down