- Fix pages rendering slanted after zoom when using RGB (non-alpha) pixmaps.
The two
QImageconstruction sites in the render pipeline were usingQImage(w, h, fmt)+memcpy(image.bits(), samples, stride * height). ForFormat_RGB888(3 bytes/pixel) Qt pads each scanline to the next 4-byte boundary, so when the rendered page width is not divisible by 4 the bulkmemcpywrote rows without the padding, shifting every subsequent row and producing a diagonal slant. Fixed by using the stride-aware constructorQImage(samples, w, h, stride, fmt).copy()at both sites, which lets Qt handle the scanline alignment internally. - Fix redundant page-image copy on every render. The render callback passed
const QImage &imagedown throughrenderPageFromImage→createAndAddPageItem→setImage(const QImage &), triggering a full pixel-buffer copy (~3–10 MB per page). Since thePageRenderResultis a local value in the callback, the image is now moved withstd::moveall the way intoGraphicsImageItem, eliminating the copy entirely. - Fix pages appearing blank during fast scrolling. The scroll handlers
(
handleVScrollValueChanged/handleHScrollValueChanged) previously only restarted the 66 ms debounce timer on each scroll event, meaningrenderPages()— and therefore any render requests for newly visible pages — would not fire until scrolling stopped. Visible pages are now queued for rendering immediately on every scroll event viarequestPageRender(); the debounce timer still fires afterwards to handle cleanup (pruning stale renders, removing off-screen items, updating preload pages). - Fix viewport jumping to the wrong page during Ctrl+scroll zoom in multi-page
continuous layout. The zoom path applies a GPU view-transform (
m_gview->scale()) immediately for O(1) visual feedback, then defers the expensiverepositionPages()bake to a 66 ms debounce timer. During the bake,resetTransform()followed byupdateSceneRect()caused Qt to auto-clamp scrollbar values and emitvalueChangedonm_vscroll/m_hscroll— beforecenterOn()had a chance to restore the correct viewport position. Becausem_gscene->blockSignals(true)only suppressesQGraphicsScenesignals (not scrollbar signals), the scroll handlers fired with an incorrect position, updated the current-page counter, and queued renders for the wrong pages. Fixed by also callingm_vscroll->blockSignals(true)/m_hscroll->blockSignals(true)around the entire bake critical section and releasing them aftersetUpdatesEnabled(true)at the end of the merged suppression window.
- Eliminate redundant work in the render cycle:
updateSceneRect()was called unconditionally at the end ofrenderPages()even when the zoom-bake block had already called it in the same cycle, causing a doublesetSceneRect()on every zoom event. It is now skipped when zoom was just baked (except in thumbnail mode where item bounds contribute to the scene rect).getPreloadPages()was re-enteringgetVisiblePages()internally even though the caller already held the result. Signature changed to accept the visible-page set as a parameter, eliminating the redundant cache lookup on every render cycle.cachePageStride()was allocating aQFontandQFontMetricsFon every call in thumbnail mode to compute the label row height, even though the value is constant for a given config. The result is now cached inm_thumbnail_label_heightand computed only once.
- Reduce default memory usage significantly. Three sources of excess allocation
have been eliminated:
- MuPDF internal store reduced from
FZ_STORE_DEFAULT(256 MB) to 64 MB. The store caches decoded embedded images, fonts, and glyph bitmaps; the old cap allowed it to silently consume the majority of the process RSS on image-heavy documents. The limit is now configurable viabehavior.mupdf_store_size(integer, MB). - Alpha channel removed from rendered pixmaps.
fz_new_pixmap_with_bboxwas called withalpha=1, producing 4-component RGBA pixmaps even though the page background is always cleared to opaque white and the alpha plane is never used. Changed toalpha=0; rendered pages are now stored asFormat_RGB888(3 bytes/pixel) instead ofFormat_RGBA8888(4 bytes/pixel), a 25 % reduction per cached and displayed page image. - OpenGL MSAA disabled. The OpenGL viewport was configured with 4× MSAA
(
format.setSamples(4)), which multiplies the GPU framebuffer size (colour, depth, stencil) by four. On integrated-GPU systems this memory is carved from system RAM and shows up directly in process RSS (~60–100 MB at 1080p). MSAA brings no quality benefit for a document viewer because MuPDF already antialiases text and images at the CPU level. Samples are now always 0. - OpenGL
CacheBackgroundremoved.QGraphicsView::CacheBackgroundallocated a redundant full-viewport pixmap for what is typically a solid-colour scene background. Replaced withCacheNone.
- MuPDF internal store reduced from
- Change default rendering backend from
Auto(OpenGL when available) toRaster. The OpenGL backend adds ~150–185 MB of driver and framebuffer overhead with no meaningful quality or performance benefit for document viewing. OpenGL remains available viarendering.backend = "opengl"in the config.
- Add narrow to region (Emacs-style). Invoke
narrow_to_region(or View → Narrow to Region) to enter rubber-band selection; the chosen rectangle becomes the entire viewport — scrolling is constrained to it, everything outside is painted over with the background colour, and all interactions (text selection, zoom, search, links) work normally within the region.wide_region(or View → Widen) restores the full document view. The narrow state survives zoom changes: the region is stored in normalised page-local coordinates and recomputed from the page item's current transform after each re-render. The narrow region is also accessible from the region-selection context menu ("Narrow to Region"). - Expose
view:narrow_to_region(),view:wide_region(), andview:is_narrowed() -> booleanin the Lua view API. - Add horizontal and vertical page flip (
flip_horizontal/flip_verticalcommands, default bindings|/_). Flip state is stored inModelalongside rotation and propagated through every coordinate-space transform (buildPageToDevMatrix/buildRenderTransformhelpers) so that text selection, link hit-testing, annotation picking, and all other page-space operations remain correct when a document is flipped. All render backends are supported: MuPDF PDF/XPS/CBZ, static images, animated GIFs, and DjVu. Commands are exposed asview:flip_horizontal()andview:flip_vertical()in the Lua view API. - Add
view:region_select(callback)Lua API. Switches the view into rubber-band selection mode; when the user draws a rectangle the callback receives{ x, y, w, h }in scene coordinates and the view returns to normal. The default context menu is bypassed so scripts can use the region for arbitrary purposes. - Add "Copy Region as Image (Custom DPI)..." to the region-selection context menu. For PDF and other vector sources the selected region is re-rendered from the cached MuPDF display list at the requested DPI (72–1200, default 300), so the clipboard image is sharp regardless of the current view zoom. Only the selected sub-region is rasterized — not the whole page. Rotation and flip state are preserved in the new render transform. For raster sources (images, DjVu) the existing crop is upscaled using smooth transformation to approximate the requested resolution.
- Add
lektra.timerLua module backed byQTimer. Timers are created withlektra.timer.new(interval_ms, callback [, single_shot]), supportstart,stop,set_interval,set_single_shot,is_active,is_single_shot,interval, anddestroy. Timers are parented to the main window so they are cleaned up automatically on shutdown; the__gcmetamethod ensures theQTimerand Lua callback reference are released as soon as the userdata is garbage-collected, making explicitdestroy()calls optional rather than required. - Add
view:rotate_clock(),view:rotate_anticlock(),view:flip_horizontal(), andview:flip_vertical()to the Lua view API (lektra.viewmethods onViewuserdata). Rotation methods were previously missing from the view API entirely. - Implement SyncTeX forward search (editor → lektra).
--synctex-forwardnow callssynctex_display_queryand jumps to the matching PDF location viaGotoLocation, including deferred-render support. Previously the flag parsed the arguments but never performed the jump (was a TODO). - Add
--socket <path>CLI flag. Starts the IPC server on the given socket path, allowing multiple lektra instances to be addressed independently (analogous tonvim --listen). The first invocation with a given socket listens; subsequent invocations with the same socket forward their message and exit. - Add
--single-instanceCLI flag. Forces single-instance mode for one invocation without requiringbehavior.single_instance = truein the config file. --synctex-forwardnow implicitly acts as single-instance: it always attempts to connect to a running instance via IPC regardless of thesingle_instanceconfig setting, preventing duplicate windows when triggered from an editor.- SyncTeX forward search via IPC now reuses an already-open tab for the target PDF instead of opening a new one each time. The matching tab is brought to focus and the view jumps to the synctex position in-place.
- Add split maximize (
split_maximizecommand). Hides all split panes except the currently focused one, giving it the full tab area. Invoking the command again restores all panes at equal sizes. Focus navigation while maximized (split_focus_*) moves the maximized slot to the newly focused pane rather than switching the active pane within a hidden layout. Creating a new split or closing the maximized view automatically restores the layout first. A small corner badge (⊠) is drawn on the maximized view; controlled bysplit.maximize_indicator(bool, defaulttrue) andsplit.maximize_indicator_color(ARGB, default0xCC2979FF). Both options are exposed in the Lua opt API aslektra.opt.split.maximize_indicatorandlektra.opt.split.maximize_indicator_color. - Add focus border for the active split pane. Three new
splitconfig options:split.focus_border(bool, defaultfalse) enables the feature;split.focus_border_color(ARGB integer, default0xFF4FC3F7) sets the border colour;split.focus_border_width(integer, default2) sets the thickness in pixels. All three are exposed in the Lua opt API aslektra.opt.split.focus_border,lektra.opt.split.focus_border_color, andlektra.opt.split.focus_border_width. - Add
portal.splitconfig option ("vertical","horizontal", or"smart"). Previously portals always opened in a vertical split."smart"automatically picks vertical when the view is wider than tall and horizontal otherwise. - Add
FilePicker— an Emacs-style find-file picker (file_pickercommand, default bindingCtrl+Shift+o). The prompt label shows the current directory (abbreviated with~); the search box filters entries in that directory. Typing a path with a/separator auto-navigates to the directory part. Tab completes the best match: directories are entered immediately, files are completed in the input. Backspace/Delete on an empty input navigates up one directory.
- Fix highlight annotation hover effect triggering on parts of a line before the
annotation starts.
HighlightAnnotationnow overridesshape()to return the union of its individual segment rects instead of the full bounding rect, so Qt's hover hit-testing only fires when the cursor is actually over a highlighted segment. - Fix background colour being overridden by the system palette colour on scroll
or zoom.
initGuiwas setting the background brush only onm_gscene(QGraphicsScene), whosedrawBackground()only fills the scene rect. Viewport areas that fall outside the scene rect (visible when zoomed out or near document edges) were painted with the system palette window colour instead of the configured background. The brush is now set on bothm_gview(QGraphicsView) — which fills the entire viewport — andm_gsceneso that the narrow-clip strip painting inGraphicsView::paintEventcontinues to read the correct colour fromscene()->backgroundBrush(). - Fix thumbnail panel defaulting to single-page layout instead of vertical.
handleOpenFileFinishedunconditionally calledsetLayoutMode(m_config.layout.mode)on every file open, overwriting the vertical layout set during thumbnail view construction. The call is now skipped when in thumbnail mode. - Fix text-selection quads persisting on screen after navigating to a different page via the thumbnail panel.
GotoPagenow callsClearTextSelection()before rendering in single-page layout mode, where the entire page is replaced. - Fix thumbnail page highlight disappearing after the page item is re-rendered (e.g. after a zoom change).
renderPageFromImagenow saves theisHighlighted()state of the old item before deleting it and restores it on the newly created item. - Fix thumbnail page highlight disappearing when a highlighted page scrolls off-screen and its item is deleted.
The highlight state is now re-applied in
renderPageFromImagewhenever an existing highlighted item is replaced, covering both the re-render and the scroll-back-into-view paths. - Fix
GoForwardHistoryalways returning immediately due to a malformed guard condition. The expressionm_loc_history_index + static_cast<int>(m_loc_history.size())(a large positive sum, always truthy) was missing a comparison operator; corrected tom_loc_history_index + 1 >= static_cast<int>(m_loc_history.size()). - Add
behavior.cache_passwordconfig option (defaulttrue). When auto-reloading a password-protected document, the password entered at open time is reused automatically. Set tofalseto prevent the password from persisting in memory beyond the initial unlock; auto-reload will then fail with an explanatory message for encrypted files. - Fix auto-reload from disk being unreliable. Three bugs: (1) the file-stability
check compared two
QFileInfosize readings taken back-to-back with no delay, so it always returned "stable" even while the file was still being written (e.g. latexmk truncates the PDF to 0 bytes before rewriting it); size is now compared across two 100 ms timer ticks. (2)QFileSystemWatcher::fileChangedcan fire multiple times for a single atomic file replace, spawning concurrent reload chains that caused double reloads; am_reload_pendingguard now prevents this. (3) The watcher path was only re-added after a successful reload, so a transient corrupt file would permanently stop watching for future saves; the re-add is now unconditional. - Fix
--single-instanceCLI flag not triggering IPC forwarding. The probe condition usedreadSingleInstanceFromConfig()(reads the TOML file) and ignored the in-memory flag set by--single-instance, so the flag only started a server but never forwarded to an existing instance. Both sources are now combined before the probe runs. - Fix SyncTeX IPC tab reuse only searching the root view of each container, missing PDFs
open in split panes. Now uses
getAllViews()to search all views in the container. - Fix window title showing
"Argument missing"warning whentitle_formatused{}placeholder in the default value ("{} - lektra"), which is incompatible withQString::arg(). Default changed to"%1 - lektra"to match the existing TOML-loading path that already performs the{}→%1substitution. - Fix crash on exit caused by
Lektra::~Lektra()callinglua_close(m_L)beforem_command_managerwas destroyed. Commands registered from Lua holdLuaRefGuardshared_ptrs whose destructor callsluaL_unref— which requires the Lua state to still be alive.m_command_manageris now explicitly reset beforelua_closeso those destructors fire in the correct order.
- Change cursor to a crosshair (
Qt::CrossCursor) when in text-highlight mode, switching to the I-beam only while actively dragging a selection. The default arrow is restored on mode exit. - Fix
BrowseLinkItemhover highlight rendering as nearly-black instead of yellow due toQColorbeing constructed with float literals(1.0, 1.0, 0.0)that were implicitly truncated to integers(1, 1, 0). Corrected to(255, 255, 0, 125). - Fix internal links targeting page 0 (the first page) being silently ignored. The guard
if (_pageno)evaluated to false for page 0; corrected toif (_pageno >= 0). - Fix float-to-int truncation in
highlightAnnotColorandDeleteAnnotationsCommand::undowherestatic_cast<int>(x * 255)could produce off-by-one values (e.g. 254 instead of 255). Now usesqRound(). - Remove duplicate non-const
Model::DPI()overload that shadowed the canonical[[nodiscard]] constversion and caused the[[nodiscard]]attribute to be bypassed on non-constModelobjects. supports_save(),supports_encryption(),supports_decryption(), andisImage()inModelwere not markedconst noexceptdespite being pure queries with no side effects.- Z-value and zoom-limit constants in
DocumentViewwere defined as preprocessor macros (#define); replaced with typedstatic constexprvalues. m_spacinginDocumentViewwas declareddoublebut initialized with afloatliteral (10.0f); corrected toint.BrowseLinkItem::_uriwas a rawchar*with no ownership contract, risking dangling pointer access when MuPDF frees the underlying string. Changed toQStringwith aconst QString &setter.
- Fix
highlightAnnotColorinModelusingstatic_cast<int>(x * 255)which could produce off-by-one color values; corrected toqRound(). - Fix
removeAnnotCommentdeclared inModel.hppbut never implemented; added the missing definition inModel.cpp. - Fix duplicate
"Animated"entry being pushed twice into the properties list for image files inModel::properties(); removed the redundant line. - Fix
get_obj_num_at_rectcallingpdf_load_pagewithout anyfz_try/fz_catchguard, which could crash on a malformed PDF or out-of-range page number. Wrapped infz_try/fz_always/fz_catchwith proper page cleanup. - Fix
getFirstCharPosusingreturninside anfz_tryblock (bypassingfz_alwayscleanup) and manually droppingpageandstext_pagebefore returning, causing a double-free when combined with thefz_alwaysblock. Replaced with afoundflag that exits the nested loops normally sofz_alwaysperforms the single correct cleanup. - Fix
ScrollDown_HalfPageandScrollUp_HalfPageusingm_page_items_hash[m_pageno]which silently inserts a null entry and immediately dereferences it, causing a crash when the current page is not yet rendered. Changed to.value(m_pageno, nullptr)with a null guard. - Fix
renderAnnotationsandrenderLinksusingm_page_items_hash[pageno](inserting null on miss) instead of.value(pageno, nullptr). - Fix
annotColorChangeRequestedlambda inrenderAnnotationsqueryingm_model->getAnnotColor(m_pageno, ...)using the current page instead of the capturedpageno, returning the wrong color for annotations on non-current pages. - Fix
renderLinksearly-return guard using&&across all three conditions, meaning an unsupported-links model only skipped rendering when the other two conditions also held. Split into two independent guards. - Fix
clearVisiblePagesremoving scene items without deleting them, leaking everyGraphicsImageItemon document close or reload. Addeddelete itembeforeremoveItem, consistent withclearVisibleLinksandclearVisibleAnnotations. - Fix
ensureSearchItemForPagereturning a cached item only when text search is not supported — the condition was inverted. Corrected toif (supports_text_search() && ...). - Fix
Copy_page_imagecallingpageAtScenePoswith a widget-spaceQPointfromviewport()->rect().center()instead of a scene-space coordinate; the result was immediately overwritten by the correct call. Removed the dead first call.
- Fix
focusView()skipping assignment ofm_current_viewwhen it wasnullptr— the guardif (m_current_view && m_current_view != view)required a non-null current view, so the first focus call after construction never setm_current_viewor emittedcurrentViewChanged. Corrected toif (m_current_view != view)with a separate null check before deactivating the old view. - Fix
closeView()emittingviewClosedbeforem_current_viewwas updated, so any slot responding to the signal would observe a stale (already deleted) current view. Moved theemit viewClosed(view)to after them_current_viewreassignment block in both branches. - Fix
closeThumbnailView()andfocusThumbnailView()being empty stubs that only checked for a nullm_thumbnail_viewand returned. Replaced with inline implementations delegating tocloseView(m_thumbnail_view)andfocusView(m_thumbnail_view)respectively. - Fix
createThumbnailView()connecting theviewClosedlambda withoutQt::UniqueConnection, causing the lambda to accumulate duplicate connections on repeated calls. AddedQt::UniqueConnectionto theconnectcall.
thumbSize = totalSize * 0.15inequalizeStretchsilently truncated adoubleresult toint; changed tostatic_cast<int>(totalSize * 0.15).- The QSplitter handle stylesheet string
"QSplitter::handle { background-color: palette(mid); }"was duplicated across five call sites inDocumentContainer.cpp; extracted to astatic const char *const SPLITTER_STYLESHEETat file scope.
HSCROLL_STEPandVSCROLL_STEPinDocumentView.cppwere preprocessor macros; replaced withstatic constexpr int.switch ((int)m_model->rotation())used a C-style cast; changed tostatic_cast<int>.img.save(fileName, format.toStdString().c_str())created a temporarystd::stringto obtain aconst char*; changed toformat.toLatin1().constData().PageDimensionCache::reset()assigned integer0to avector<bool>; corrected tofalse. C-style casts(int)inset(),getOrDefault(), andget()replaced withstatic_cast<int>.- Redundant
reserve()calls before copy-assignment oflinksandannotationsvectors inrenderPageWithExtrasAsyncremoved; copy-assign allocates its own storage.
-
LRUCache::putunconditionally calledremove(key)before every insert, incurring a redundant map lookup for the common new-key path. Inlined the existence check to avoid the extra traversal. -
trim_wsinutils.hpptrimmed leading whitespace with a per-charactereraseloop (O(n²)); replaced with a singleerase(begin, find_if_not(...))call. -
GraphicsImageItem::height(),quad_y_center(), andcharEqual()were missingnoexceptdespite being trivially non-throwing; added for consistency with surrounding functions. -
Show_highlight_search()andShow_annot_comment_search()used&&instead of||in their null-guard (!m_doc && !m_doc->model()->...), causing a null pointer dereference whenm_docwas null. Corrected to||. -
Tab_gotobounds check used||instead of&&(index > 0 || index < count), making the condition almost always true and allowing out-of-range indices to pass. Corrected toindex >= 1 && index <= count. -
ShowAboutleaked anAboutDialoginstance on every call since the dialog was heap-allocated but never freed. AddedWA_DeleteOnCloseso each dialog self-destructs when closed. -
OpenFilesInNewTabwarning message claimed extra files would be processed with no callback, but the function returned immediately. Message updated to accurately state that the operation is aborted. -
std::movewas called on aconst QStringList ¶meter inOpenFilesInNewTab,OpenFilesInVSplit, andOpenFilesInHSplit, silently falling back to a copy. Corrected to plain assignment; the lambda captures in VSplit/HSplit now moveqfilescorrectly. -
Fix
n/Nsearch navigation skipping hits on the current page and jumping directly to the next/previous page.getClosestHitIndexnow steps by flat hit index when the current hit is on the visible page, falling back to page-level anchoring only when the user has scrolled to a different page. -
Scrollbars are kept visible while search hit markers are drawn on them (
scrollbars.search_hits = true). The auto-hide timer and mouse-leave events no longer dismiss the scrollbar during an active search; normal auto-hide resumes once the search is cancelled or cleared. -
Fix jump marker rendering at the wrong position after a zoom change. The marker's location is now stored as a
PageLocation(page + document-space coordinates) instead of a scene-space point, soReshow_jump_markerrecomputes the correct scene position at call time regardless of zoom level.
- Add Comment to the text selection context menu. Selecting text and choosing Comment now opens an input dialog, then creates a highlight annotation with the comment embedded as a single undoable operation — no need to first highlight and then right-click the annotation to add a comment.
- Add Copy Text to the highlight annotation context menu. Copies the exact highlighted text to the clipboard by testing each character's centre against the annotation's quad points, using the cached stext page so no extra parsing is needed.
- Ability to open multiple files using file dialog to open in new tab, vsplit or hsplit.
DocumentViewno longer inheritsQOpenGLWidget— it is a plainQWidgetthat hosts theGraphicsView; all GPU work goes through the view's ownQOpenGLWidgetviewport.- Touch events are now correctly re-applied to the new viewport after
applyBackend()replaces it. - A global
QSurfaceFormat(depth 24, stencil 8) is set beforeQApplicationconstruction to ensure a well-formed OpenGL context on all platforms.
- New dispatch event
OnShutdown- Dispatched when the application is shutting down
- Event callbacks now receive typed arguments instead of a raw
Lektrapointer for events where more specific data is available:OnScreenChanged— callback receives aScreenInfotable with fields:name,dpr,logical_dpi,physical_dpi,refresh_rate, andgeometry({x, y, w, h})OnTabChanged,OnTabRemoved— callback receives the tab index as an integer
- Lua stubs:
ScreenInfoclass added with full field annotations
- Save File menu action is now enabled only when the document has unsaved changes,
providing a clear visual signal of modified state. A new
modifiedChanged(bool)signal onDocumentViewdrives the update so the menu reacts immediately on each edit. - File Properties menu action is now enabled for all open file types, not just PDF.
- Back / Forward history navigation actions are now enabled only when there is actually
somewhere to navigate:
canGoBack()andcanGoForward()methods were added toDocumentView, ahistoryChanged()signal is emitted fromaddToHistory,GoBackHistory, andGoForwardHistory, and a dedicatedupdateHistoryNavigationActions()keeps the menu items in sync on every history change and on tab switch. - Invert Colour menu item checked state is now synced on tab switch. Previously
switching between tabs with different invert states left the checkbox stale; it is now
updated in
updateUiEnabledState. - Fix annotation comment edits (right-click annotation → Add Comment) not being tracked by
the undo stack. Comments are now pushed as
AnnotCommentCommandentries, so they can be undone/redone correctly and the modified indicator stays in sync. - Fix save being available after a save → undo → redo cycle. The undo stack correctly
returns to its clean index on redo, but MuPDF's internal mutation tracker still reported
unsaved changes because it sees the undo and redo as two separate edits.
SaveFilenow usesm_is_modified(driven by the undo stack's clean state) rather thanpdf_has_unsaved_changesto decide whether a save is needed. - Fix zoom glitch in multi-page document mode: interactive zoom (pinch/scroll) now uses an
O(1) GPU view-transform (
QGraphicsView::scale) for each step, deferring the O(n)repositionPages()call until the scroll-debounce timer settles. This eliminates the jarring per-page resize flash that was visible during zoom. - Fix multi-page text selection breaking when scrolling: pages within the active selection
range are now protected from eviction by
removeUnusedPageItems, preventing gaps in the rendered quads andpageAtScenePosfailures on the anchor page. - Fix fit mode not working properly for images/djvu files after rotating
- Fix pickers (command palette, outline, bookmarks, etc.) leaking key events and shortcuts
to the focused
DocumentViewwhile open. Pickers now grab the keyboard on launch and install an application-level event filter to swallowQShortcutEvents, both of which are released on dismiss or item acceptance. - Fix
InputDialogok and cancel buttons looking flat and weird. - Render highlight annotations spanning multiple lines correctly by splitting the annotation quad into separate quads for each line. Previously, single rectangular quad spanning the multi-line highlight was rendered.
- Add Lua API
view:export_highlights(path)that serialises all highlight annotations to a JSON file. Each entry containspage(1-based),text, and optionallycomment. Returnstrueon success ornil, erroron failure.
- Fix crash when right-clicking on the overlay scrollbar — right-click events were
unconditionally forwarded to the scrollbar, causing its built-in context menu
(
QMenu::exec) to spin a nested event loop whileGraphicsView::contextMenuEventalso fired, leading to a double-menu crash. Non-left-button clicks on the scrollbar are now silently ignored. - Fix animated GIF frames being skipped:
QImageReader::read()auto-advances the frame position for animated formats, so the subsequentjumpToNextImage()call was double-advancing and skipping every other frame. - Fix animated GIF playback running at ~1.5× speed: the elapsed clock was started before the first timer fired, so the first callback measured ~100 ms of wait time as "render overhead" and scheduled the next frame at 0 ms delay. Subsequent frames alternated between 0 ms and ~95 ms, averaging half the intended interval. The clock is now restarted at the top of each callback so it measures only actual render overhead.
- Fix image files always rendering blurry: pixel dimensions were stored directly as
typographic points in the page dimension cache, causing
pageSceneSizeandrepositionPagesto apply an extra ×(dpi/72) upscale on every render. Dimensions are now converted to pts (px * 72 / dpi) on load, matching the DjVu path. - Fix image zoom leaving blurry pixels:
setZoomAnchoredfor images only applied a Qt scene-transform scale and never triggered a pixel-level re-render. The HQ render timer is now started after each anchor zoom so that, once zoom settles,renderImagere-renders at the exact target dimensions usingQt::SmoothTransformation. - Add
collectHighlightTexts()onModelreturning astd::vector<HighlightText>withpage,text,comment, andquadfields. Multi-line highlights are grouped into a single entry (lines joined with a space) rather than one entry per line.
- Animated GIF memory usage reduced from O(all frames) to O(1 frame): switched from
pre-decoding every frame into a
QList<QImage>buffer toQMoviewithCacheMode::CacheNone, which decodes one frame at a time on demand. The manual timer and elapsed-clock machinery is replaced byQMovie::frameChanged.
- SVG files are now rendered via librsvg + Cairo when available, with automatic fallback
to Qt's
QSvgRenderer. librsvg is probed at runtime usingQLibrary(no build-time dependency, no configuration flag) — iflibrsvg-2.so.2andlibcairo.so.2are installed on the system they are used automatically, otherwise rendering falls back silently. librsvg handles CSS class-based styles,<switch>fallback elements, and CSS functions such aslight-dark()that Qt's renderer ignores, producing correct output for SVGs generated by tools like draw.io.
- DjVu support is now detected at runtime via
QLibraryinstead of requiring a compile-timeWITH_DJVUflag and a link-time dependency on libdjvulibre. If it is installed on the system, DjVu files are opened automatically; if it is absent, DjVu is silently unavailable. TheWITH_DJVUCMake option and theHAS_DJVUpreprocessor define have been removed.
- Remove
ImageMagickdependency as it's a headache to maintain and to link against for cross-platform compatibility. - Removed
lektra.capabilitiestable as it's not useful
-
Auto scroll on text selection mode to keep the selection in view when selecting text with the mouse or keyboard, which provides a smoother and more intuitive text selection experience, especially for longer documents where the selected text may go out of view.
-
Add optional lua scripting support (experimental, work in progress)
-
API overview
lektra.opt- for getting and setting config optionslektra.cmd- for command related stufflektra.ui- for UI related stuff (e.g. showing notifications, input dialogs, etc.)lektra.tabs- for managing tabslektra.event- for subscribing to events (e.g. page change, file open, etc.)lektra.keymap- for managing keybindingslektra.mousemap- for managing mousebindingslektra.utils- for utility functionslektra.version- for version functionslektra.capabilities- for querying about compiled optionslektra.bookmarks- for managing bookmarks
-
Check LUA-WIKI.md for more details and examples of the lua scripting support in LEKTRA.
-
-
Vim/Emacs like search hit indexing navigation if
absolute_jump = falsein[search] -
Add bookmarks support with a bookmark picker to view and manage bookmarks. Bookmarks allow users to save specific locations in the document for quick access later.
-
New bookmark related commands:
bookmark_addto add a bookmark at the current locationbookmark_removeto remove a bookmark at the current locationbookmarksto open the bookmark picker with the list of bookmarks in the document
-
Add image rotation support
-
Add missing implementation for
single_instanceoption. Now ifsingle_instanceis enabled, new files will use the existing instance of LEKTRA instead of opening a new instance, which allows for better management of multiple documents and prevents cluttering the taskbar with multiple instances of LEKTRA.
- Fix crash when right-clicking on the overlay scrollbar — right-click events were unconditionally
forwarded to the scrollbar, causing its built-in context menu (
QMenu::exec) to spin a nested event loop while the GraphicsView'scontextMenuEventalso fired, leading to a double-menu crash. Non-left-button clicks on the scrollbar are now silently ignored. - Update the layout menu item names
- Fix crash (SEGV) on click selection in
SINGLElayout mode —pageAtScenePoswas guarding theoutPageItemassignment withif (outPageItem), but the pointer is alwaysnullptrat that point, sopageItemwas never set andmapFromScenedereferenced null. - Fix wrong text selection after zoom in
SINGLElayout mode —setZoomAnchoredcalledrepositionPages()(which scales the old item as a visual intermediate) but never triggered a re-render, leaving the page item permanently at a non-unity scale. BecausemapFromScenedivides by the item scale, selection coordinates were passed tocomputeTextSelectionQuadin the wrong zoom space. Fixed by callingrenderPage()forSINGLEmode afterrepositionPages()insetZoomAnchored. - Fix fit mode not working if image files are opened
- Fix memory leak in
extractTextfunction inModelclass - Add UTF-8 text conversion for file paths on Windows to fix issues with opening files with non-ASCII characters in their paths on Windows.
- Reset
m_success = falseat the start of every open inModel.cpp - [DocumentView.cpp] Made the future watcher connection single-shot and cleared stale connections before reconnecting and
added a guard in
handleOpenFileFinished()so it exits early if the model did not actually open the file. - Add missing
pageconfig section loading from the config - Fix visual line mode navigation to be more naturally
- Fix context menu on tabs not working
- Fix opening files in containers with already open file not loading.
- Fix
openSessionFromArrayfunction loading files incorrectly and breaking - Fix segfault in
buildPageCachebecause of double free of mupdf context - Add implementation for
file_reloadcommand - Fix synctex initialisation
- Fix synctex optional macro in the source code
HAS_SYNCTEX->WITH_SYNCTEX - Fix image zoom anchoring
lua/Lektra.cpp: Fix stack leak inexecuteLuaCode— the message-handler function was pushed beforeluaL_loadstringbut never popped, growing the Lua stack by one slot on every call. Replaced withlua_settopsave/restore and removed the broken handler (which returned 0 instead of the required 1 value). Also fixedtoStdString().c_str()to a stableQByteArraylocal.lua/view.cpp: Fixopenmethod readinglua_upvalueindex(1)with zero upvalues — caused undefined behaviour/crash. Now resolves theLektrainstance viaqobject_cast<Lektra*>((*view)->window()).lua/view.cpp: Fixfit,mode, andlayoutgetter methods returning0(no values) after pushing a value onto the stack — callers received garbage. Changed toreturn 1.lua/view.cpp: Fixgoto_locationapplying a page-index offset twice:pagenowas already converted to 0-based, then subtracted again before passing toGotoLocation, sending page 1 to index −1.lua/view.cpp: Fixzoomcontaining unreachablereturn 0afterreturn 1in both branches. Collapsed to a single push +return 1.lua/view.cpp: Fixset_invertreturning 1 in the success branch without pushing anything — now returns 0 (setter, no return value).lua/view.cpp: Replace empty stub bodies inset_modeandsave_aswithluaL_errorso callers get a clear error instead of silent no-ops.lua/event.cpp: FixunregisterAPI mismatch — it expected(string, int)butregisterreturns only aninthandle. Unified to(EventType, handle)matching theregistersignature.lua/event.cpp: Fixoncetaking a string event name whileregistertakes an integerEventType. Both now use integerEventTypefor consistency.lua/event.cpp: FixCOUNTsentinel exposed in thelektra.event.EventTypeLua table due to an off-by-one<=in the population loop. Changed to<.lua/event.cpp: Fixoncecallbacks never being removed —is_onceflag was set butdispatchLuaEventnever checked it, so the callback would fire on every subsequent dispatch (pushing nil after the first unref). Moved cleanup intodispatchLuaEventusing an erase-remove pass after invocation.lua/event.cpp: Fix iterator invalidation indispatchLuaEvent— callbacks could callunregisterduring iteration. Now iterates over a local copy of the callback list.lua/cmd.cpp: Fix Lua registry reference leak on command unregister —func_refwas captured in the action lambda butluaL_unrefwas never called when the command was removed. Wrapped in ashared_ptrguard whose destructor callsluaL_unref.include/DispatchType.hpp: Fix duplicateOnPageChangedkey in the dispatch map — the second entry silently overwrote the first inQHash.include/DispatchType.hpp: Rename reserved identifier__dispatchEventMap(double leading underscore is reserved by the C++ standard) tos_dispatchEventMap.include/DispatchType.hpp: Replace O(n) linear scan indispatchTypeToStringwith an O(1) static array indexed by enum value.
-
lua/view.cpp: Implementview:outline()— returns the document table of contents as a recursive Lua table tree. Each entry hastitle,pageno(1-based,nilfor external links),x,y, and achildrenarray for nested headings. -
Model.cpp/DocumentView.cpp: Overhaul animated image (GIF) playback performance:- Two-pass open:
pingImagesreads frame count and per-frame delays from headers only (no pixel I/O). A single[0]scene read then decodes frame 0 and emitsopenFileFinishedimmediately, so the image appears without waiting for the full decode. Remaining frames are decoded in a background thread viareadImages+coalesceImages. - Remove dead
getAnimatedFrame: the function re-read and re-coalesced the entire file from disk on every call just to produce one frame. It was never called; removed entirely. - Eliminate
m_image_cacheindirection for animated frames:setCurrentAnimFramenow only updatesm_current_frame;requestImageRenderreads directly fromm_animated_frames[m_current_frame], removing a per-advance QImage copy. - Remove unconditional
qDebuginsetCurrentAnimFrame: the debug log fired on every frame advance (30+ times per second in all build configurations). - Fix
cleanup_imagenot resetting animated state:m_animated_frames,m_frame_delays_ms,m_frame_count, andm_current_framewere left populated when switching away from an animated image. - Frame-skip during startup: the playback timer skips frames that have not been decoded yet (background decode still in progress) instead of displaying a blank frame.
- Elapsed-time frame scheduling: the animation timer now subtracts actual render time
from the next frame's nominal delay via
QElapsedTimer, keeping the playback cadence on schedule even when individual frames render slowly. - Free raw Magick frames early: in the background decode path, the raw
readImagesvector is cleared immediately aftercoalesceImagesso decoded-but-uncompressed Magick memory is released before the QImage conversion loop begins.
- Two-pass open:
-
DocumentView.cpp: ReplaceQGraphicsItem::data(0).toString()tag checks withQSet<int>membership tests (m_placeholder_pages,m_preload_pages) eliminating repeatedQVariant→QStringconversions in hot loops insideremoveUnusedPageItems,repositionPages, andrenderPages. -
DocumentView.cpp: Split the single render queue into a visible-page queue and a preload queue sostartNextRenderJobdequeues in O(1) instead of doing an O(n) linear scan with an O(n)removeAtto find the next visible page to render. -
DocumentView.cpp: EliminateQHash::keys()heap copies inremoveUnusedPageItems,clearVisibleLinks, andclearVisibleAnnotations; replaced with direct iteration or a two-pass collect-then-delete approach. -
DocumentView.cpp: Cache the last rendered search-hit state (index+ page-item pointer) inupdateCurrentHitHighlightso the path is only recomputed when the hit or page item actually changes, avoiding redundantQPainterPathrebuilds on every scroll event. -
Model.cpp: Skip redundantline_length()traversal infind_closest_in_pagefor lines with no characters — the call always returned 0 so theidxincrement was a no-op. -
Model.cpp: Hoistm_inv_dprscale constant out of the per-link and per-annotation render loops inrenderPageWithExtrasAsync; addreserveonresult.linksandresult.annotationsbefore those loops to avoid reallocation churn on pages with many links or annotations. -
Lektra.cpp: HoistfindChildren<QShortcut *>()out of the per-key loop insetupKeybinding— was performing a full child-object tree traversal once per key; now called once before the loop with deleted entries removed in-place to avoid dangling pointers. -
Lektra.cpp: Replace the temporaryQStringList() << "*.json"filter construction ingetSessionFileswith astatic const QStringList, eliminating a heap allocation on every call.
- Remove
placeholder_textoption from[command_palette]section of the config. - Add
promptoption in[picker]common to all pickers, which allows for a customizable prompt text shown next to the input field. - Rename
always_open_in_new_windowtosingle_instance. - C++ version requirement has been downgraded to C++20 (previously it was C++23) to allow for wider compatibility with different platforms and compilers, as C++20 is now widely supported by most modern compilers and platforms, while C++23 is still very new and not yet supported on many platforms.
-
Synctex is now bundled with LEKTRA instead of using the system installed synctex, which should improve synctex support and make it available on all platforms without requiring users to install synctex separately. This can be disabled by passing
--without-synctexin the configure script. -
Add optional
Imagemagickimage rendering library support for handling more image file formats.- Requires ImageMagick to be installed on the system and
Magick++development libraries for compilation.
- Requires ImageMagick to be installed on the system and
-
Animated image support (e.g. animated GIFs, WEBP, AJPG) using
ImageMagickfor rendering. -
Hide unrelevant actions from the menu bar based on the file type of the currently opened document.
-
Add
Windowsoperating system support -
Add "pan" mouse action in
[mousebindings]section. Used for panning around the page my clicking and dragging the mouseExample:
[mousebindings] pan = "Alt+LeftButton"
-
New actions in
[picker.keys]section:expand: if on a heirarchy node, expand it (inflat_mode = false) (default:Tab)collapse: if on a heirarchy node, collapse it (inflat_mode = false) (default:Tab)section_prev: move to the previous section (e.g. previous chapter in the outline picker) (default:Ctrl+Shift+k)section_next: move to the next section (e.g. next chapter in the outline picker) (default:Ctrl+Shift+j)
-
Default mouse bindings:
pan=>Alt+LeftButtonpreview=>Alt+Shift+LeftButtonportal=>Ctrl+LeftButtonsynctex_jump=>Shift+LeftButton
-
Searching now searches from the current page/location to the end of the document.
- Add ImageMagick to the
AboutDialog'slibraries usedsection - Stop animated image playback when not visible (different tab) to save resources and avoid unnecessary CPU usage.
- Hide mode, color and progress info in the statusbar when in non-supported file types (e.g. images) to avoid confusion
- Fix
invert colormenu button not working - Make search behave more like in vim/emacs
- Fix linux
#ifdefs - Set minimum size for the
InputDialogwidget - Remove redundant file dialog formats
- Picker
next,prevnavigation now goes through all the items instead of just the top level items when inflat_mode = false(hierarchical mode), which makes navigation in the picker more intuitive and consistent regardless of the mode. - Picker not navigable when search bar is opened. (Issue reported by: @linewaytin)
- Fix
--check-confignot working with[keybindings],[mousebindings]sections. (Issue reported by: @lineick) - Don't null out the statusbar item spacings which caused the statusbar items to have 0 padding and look weird.
- Fix
ColorDialognot showing up the colored buttons. - Make
RecentFilesPickerbe flat structured by default instead of hierarchical (it makes more sense to have flat structure) - Handle
Esckey to quit open pickers.
- Remove
search_from_herecommand as it's not useful anymore since the default behavior is to search from the current location. - Move
sessionsandlast_pages.jsonfile toQStandardPaths::AppDataLocationfor better compliance with platform standards for application data storage (previously stored in theQStandardPaths::AppConfigLocation, which is meant for configuration files). - Remove LLM support (current implementation was not good), but it will be added back in the future with a better implementation.
- Removed shell scripts support as it was never implemented and there are no current plans to implement it.
-
Organised
[statusbar]components into it's own sections.[statusbar.component]for the actual components to show in the statusbar and their order[statusbar.component.mode]for the interaction mode component settings[statusbar.component.filename]for the file name component settings[statusbar.component.zoom]for the zoom indicator component settings[statusbar.component.pagenumber]for the split indicator component settings[statusbar.component.progress]for the link hint indicator component settings
-
Ability to have configurable colors in the Color Dialog
[misc]
color_dialog_colors = [ "#FF500055", "#FF000055"] # Can have any number of colors-
Add some more spanish translations.
-
Absolute vs Relative search hit jump
-
Thumbnail panel for quick navigation and visual overview of the document pages. The thumbnail panel can be toggled with the
thumbnail_panelcommand and will show a scrollable list of page thumbnails on the side of the window. Clicking on a thumbnail will navigate to that page in the main view. -
Default keybindings added for the following:
split_horizontal=>Ctrl+W,ssplit_vertical=>Ctrl+W,vsplit_focus_left=>Ctrl+W,hsplit_focus_right=>Ctrl+W,lsplit_focus_up=>Ctrl+W,ksplit_focus_down=>Ctrl+W,jsplit_close=>Ctrl+W,c
-
Add
--check-configcommand line argument to check the validity of the config file and print any errors or warnings without launching the application.
-
flat_menuoption for[outline],[highlight_search]picker. Iftrue, the picker will show all entries in a flat list without indentation, otherwise it will show entries in a clickable node structure -
Ability to set
widthandheightof pickers (outline, highlight search, recent files etc.)- These take either absolute pixel values (integers > 1) or fractional values in the range (0.0, 1.0] to size the picker relative to the window dimensions. These options apply globally to all picker types (outline, highlight, search, etc.); each picker type can override them individually in its own configuration section.
For example:
[picker] width = 0.3 # 30% of the window width height = 400 # 400 pixels height [outline] width = 0.25 # 25% of the window width for the outline picker
Here, the default width for all pickers is set to 30% of the window width, but the outline picker specifically overrides this to be 25% of the window width. The height for all pickers is set to 400 pixels.
-
Move synctex settings to their own section
[synctex]for better organization and maintainability of the config fileenabled(bool): Enable/Disable synctex supporteditor_command(string): Command to open the editor for synctex jump (e.g.code --goto {file}:{line}:{column})
-
[thumbnail_panel]section for thumbnail panel related settingsshow_page_number(bool): Whether to show page numbers on the thumbnailspanel_width(float): Width of the thumbnail panel as a ratio of the main window width (e.g. 0.2 for 20% of the main window width)
-
Ability to define multiple keybindings for same action using TOML array
Example:
[picker.keys]
up = [ "Ctrl+k", "Up" ]
down = [ "Ctrl+j", "Down" ]
[keybindings]
command_palette = [ ":", "Ctrl+P" ]Note
Notice that multiple keybindings use [] square brackets and not {} curly braces,
which have a different meaning in TOML
- Removed
synctex_editor_commandfrom[behavior]section and moved it to[synctex]section aseditor_command dim_inactiveis now disabled by default (which was enabled previously out of the box)confirm_on_quitis now false by default (I feel it was annoying).- Renamed config options:
window_title->title_formatin[window]section
- Delete Annotation Command now remembers the annotation color (if set) or defaults to the current color.
- Fix
setZoomandsetZoomAnchoredrecursive calls which caused stack overflow and crashing when zooming in/out rapidly. - Fix memory leak due to not clearing up the
trackercustom image device in MuPDF after rendering, which caused memory usage to grow indefinitely when navigating through pages. - Fix memory leak due to wrong usage of
QFutureSynchronizerwhich caused huge memory usage and slowdown when scrolling through pages. - Don't count thumbnail view in a container as a regular split when showing the total count of the splits in a container
- Fix file properties not working
- Fix crash when trying to save file after adding annotation.
- Replaced Qt's
QColorDialogwith a custom color picker dialog for annotation color selection. - Moved
Translationsdirectory to the root of the project (preivously it was insrcdirectory). - Moved
.hppheader files intoincludedirectory (previously they were insrcdirectory) for better organization of the codebase and to follow common C++ project structure conventions. - Renamed
CommandPalette.shortcutstoCommandPalette.show_shortcutsfor better clarity of what the option does.
- Add progressive searching for search results. When a search query is entered, the search results will start showing up immediately as they are found, instead of waiting for the entire search to complete before showing any results. This is enabled by default.
- Annotation color change is now undo-able.
progressive(bool) option in the[search]section of the config to enable/disable progressive searching.highlight_matches(bool) option in the[search]section of the config to enable/disable highlighting of search matches in the document. When enabled, all search matches will be highlighted in the document, otherwise only the current search match will be highlighted.load_defaults(bool) in[keybindings]section to load default keybindings. This allows users to choose whether they want to start with the default keybindings or start with an empty keybindings configuration, which can be useful for users who want to fully customize their keybindings without having to override the defaults.
--commandto execute one or more commands directly from the command line when launching LEKTRA. This allows users to quickly perform specific actions or set up their workspace with predefined commands without having to open the command palette after launch. Multiple commands can be executed by separating them with a semicolon (e.g.lektra --command="toggle_fullscreen;search 'hello'"to launch in fullscreen mode and open the config file immediately).--list-commandscommand line argument now prints the lektra commands in sorted order--versionand--list-commandsnow output to stdout instead of stderr to be more consistent with standard command line tool behavior and to allow for easier parsing of the output when using these commands in scripts or other command line workflows.- Lektra can now accept arguments directly from the command line when using
--commandargument, allowing for more flexible and powerful command execution. For example, you can now execute a command with specific arguments directly from the command line like this:lektra --command="page_goto 5;"to go to page 5 immediately after launching LEKTRA.
open_configcommand to open the config file in the default text editor for easy editing and customization of settings.scroll_down_half_page,scroll_up_half_page, commands for more precise scrolling control, allowing users to scroll by half a page in the specified direction for better navigation through documents.search_from_hereto start a search from the current page and position instead of the beginning of the document, which is useful for long documents when you want to search for something that appears after your current location without having to scroll all the way back to the beginning to start the search.search_cancelto cancel an ongoing search operation
- Fix page scrolling stuttering because of the
visual_line_modefix - Fix file drag and drop not working
- Fix
visual_line_moderect offset when zooming in/out, which caused the visual line selection rectangle to be misaligned with the text when zoom level changes. - Fix current search highlight not updating properly when zooming in/out or resizing the window, which caused the highlight to be in the wrong position or not visible after zooming or resizing.
- Fix picker hide on mainwindow with no tabs open. It caused no shortcuts to work because the mainwindow was no longer focused after the picker was shown once and then hidden.
- For real this time, fix the statusbar 0 padding
- Make different types of Picker (e.g. outline picker, search highlights picker, recent files picker, etc.) inherit configuration options from the common base
Pickerclass configuration to reduce code duplication and improve maintainability of the codebase. - Make the same inheriting structure for
Annotationconfiguration
OutlinePickernow highlights the current page in the outline for better visual feedback on the current location in the document when navigating with the outline.- Add
--list-commandscommand line argument to print the list of available commands with their descriptions to the console and exit. - Added
fade_durationto[jump_marker]config section to configure the duration of the fade out effect for the jump marker in seconds. - Finally added
Ctrl + Mouse Wheelzooming! - Config option for
[zoom]to choose whether zoom should be anchored at mouse position or center of the viewport. This can be configured with theanchor_to_mouseoption. Otherwise, zoom will be anchored to the center of the viewport as it was before. - Added macOS support for LEKTRA. Check out installation instructions for more details. (Thanks to @budingZou for the PR!)
- Added custom input dialog with text wrapping for annotation comment input, which allows for better user experience when adding comments to annotations, especially for longer comments that require more space. The dialog will automatically adjust its size based on the content and provide a more comfortable interface for entering annotation comments.
- Fix dismiss key not working in Pickers
- Don't allow searching in unsearchable file type (e.g. DJVU)
- Fix
selection_lastnot working properly. - Handle failed to open file properly by showing an error message and closing the tab cleanly.
- Fix file not focusing when opened from the recent files picker.
- Fix viewport center anchor zoom not centering on the actual center of the viewport. (Feels more natural now)
- Now pinch-zoom respects the mouse position anchor instead of the center of the viewport
- Fix spawning multiple instances of
AboutDialog
- Add man pages for command line usage documentation
man lektra - Rename
paneltostatusbar
- Add ability to not invert images in invert mode (valid in PDF, EPUB, MOBI, XPS, FB2) . Useful for users who want to use the invert mode for dark mode but don't want their images to be inverted. This can be configured in the settings with the
dont_invert_imagesoption under the[behavior]section of the config. - Add search history to the search bar, allowing users to easily access their previous search queries and results. The search history can be navigated using the
upanddownarrow keys when the search bar is focused, and selecting a previous search query from the history will re-run that search and show the results. - Ability to "preview" links by executing a mouse binding (Alt+LeftClick by default) on a link to open a temporary view of the link target without actually navigating to it in the current view in a floating window.
- "preview" config section
[preview]
size_ratio = {0.5, 0.5} # width and height ratio of the preview window compared to the main window
border_radius = 8 # border radius of the preview window in pixels
close_on_click_outside = true # whether to close the preview window when clicking outside of it-
Add
previewcommand, which shows the preview window (if it was created already) for the current link target. The preview window will be created on the fly when the mouse binding is executed on a link for the first time, and will be reused for subsequent previews of the same link target. -
Add mousebindings to allow users to configure mouse interactions (e.g. mouse click, double click, right click, mouse wheel, etc.) with different modifiers (e.g. Ctrl, Shift, Alt) to trigger different mouse related commands. Mouse commands:
portal- open link in portal (ctrl + click on link)syntex_jump- jump to source location in synctex enabled PDFs
-
Add
backendoption in[rendering]section of the config to choose between "auto", "opengl" and "raster" rendering backends. The "auto" option will choose the best available backend based on the system capabilities, with a preference for OpenGL when available for better performance.
[rendering]
backend = "auto" # "auto", "opengl", "raster"- Add
--tutorialcommand line argument to open the tutorial PDF file directly from the command line without having to open the command palette and search for the command. This is useful for new users who want to quickly access the tutorial file and learn how to use LEKTRA. - Add touchpad gesture support for zooming (pinch to zoom)
- Splitting view now takes you to the same page and location in the new split instead of the first page, which provides a more seamless experience when splitting the view to reference different parts of the same document side by side.
- Improved text selection. Text selection is now more responsive and accurate, especially for multi-columned layouts. It should now be less jumpy and more stable when selecting text across columns and pages.
- Fix Outline picker not going to the correct page and position when selecting an entry (if target location has NaN, then default to the center of the page)
- Fix portals and preview docs appearing blurry due to not using the correct DPR for rendering
- Fix remove item 0 warning in QGraphicsScene when closing document
- Fix double memory free crash on DJVU files
- Fix link hints mode not intercepting key presses properly
- Add all supported file types to the file open dialog filter
- Fix the QPainterPath pixel max limit error when text selection is too large by using page local coordinates instead of viewport coordinates for the selection path, which should allow for larger selections without hitting the pixel limit.
- Fix opening tutorial file not working due to wrong file path
- Fix djvu code under non-djvu builds causing compilation errors
- Fix optional dependency locator in
CMakeLists.txt
- Removed
gridoption from[command_palette]section of the config as it was not implemented.
- Add support for language translation and localization
- Support for running shell scripts
- Support for DJVU files (limited, only basic rendering and navigation, no text selection and searching)
- New command line argument
--layoutto specify the default layout mode on file open (e.g.--layout=bookto open in book layout mode) - Support for adding comments to annotations in LEKTRA. (After creating an annotation, you can add a note to it by right clicking on the annotation and selecting "Comment" from the context menu. This will open a dialog where you can enter your comment. Once added, the comment will be associated with the annotation. Note: These comments do not exist in the undo/redo stack, which means that if you change comment of an annotation and then undo, the comment change will not be undone. This is to do with limitations in the way the annotation data is stored and handled in the current implementation, but it might be improved in the future by integrating note changes into the undo/redo stack.
- Annotations with comments optionally can show a marker (e.g. an icon) to indicate that there's a note associated with the annotation, and hovering over the annotation will show the note as a tooltip (configurable in settings).
- Annotations have an optional hover glow effect to provide visual feedback when hovering over annotations, making it easier to identify and interact with them.
- Picker widget now supports n columns
CommandManagerclass to manage commands instead of general hash map, which allows for better organization and management of commands, as well as support for command descriptions, useful for documentation and purpose.
- `show_page_number` (bool)
- `indent_width` (int)
NOTE: This is just a convenience table to increase the readability of the config, it has no effect on its own, the actual annotation type tables (e.g. [annotations.highlight], [annotations.popup], etc.) still need to be configured separately for their respective annotation types.
- `hover_glow` (bool) to enable/disable hover glow effect on highlight annotation
- `comment` (bool) to show the comment of the highlight annotation as tooltip on hover (if the annotation has a comment)
- `comment_marker` (bool) to show a marker (e.g. an icon) on the annotation if it has a comment, to indicate that there's a comment associated with the annotation
- `glow_width` (int) to set the width of the hover glow effect on highlight annotation
- `glow_color` (RGBA hex value) to set the color of the hover glow effect on highlight annotation
- `comment_font_size` (int) to set the font size of the comment tooltip for highlight annotations
- `hover_glow` (bool) to enable/disable hover glow effect on popup annotation
- `glow_width` (int) to set the width of the hover glow effect on popup annotation
- `glow_color` (RGBA hex value) to set the color of the hover glow effect on popup annotation
- `glow_width` (int) to set the width of the hover glow effect on rect annotation
- `hover_glow` (bool) to enable/disable hover glow effect on rect annotation
- `comment` (bool) to show the comment of the rect annotation as tooltip on hover (if the annotation has a comment)
- `comment_marker` (bool) to show a marker (e.g. an icon) on the annotation if it has a comment, to indicate that there's a comment associated with the annotation
- `glow_color` (RGBA hex value) to set the color of the hover glow effect on rect annotation
- `comment_font_size` (int) to set the font size of the comment tooltip for highlight annotations
enabledoption in[links]to enable/disable links
- `match_color` (RGBA hex value) to set the color of the search hit highlights
- `index_color` (RGBA hex value) to set the color of the current search hit highlight
- Pass
structconst reference of only the respective members instead of the wholeConfigstruct.
toggle_annot_comment_marker- Toggle the comment marker on annotations that have comments (e.g. show/hide the icon indicating that there's a comment associated with the annotation)none_mode- Switch to none interaction mode where no interaction mode is activepicker_annot_comment_search- Open the picker with the list of annotations that have comments, and searching by the comment text. Selecting an entry will jump to the annotation location.
- Rename
LEFT_TO_RIGHTlayout tohorizontalandTOP_TO_BOTTOMlayout toverticalfor better clarity and intuitiveness. - Renamed
layout_left_to_rightcommand tolayout_horizontalandlayout_top_to_bottomcommand tolayout_verticalto reflect the renamed layout modes. - Command palette is now opened with ":" key by default instead of "Ctrl + Shift + P" to stay close to the Vim way of opening command palette and also because it's more ergonomic to open with a single key press.
- Renamed
[markers]to[jump_marker] - Removed
[color]section from config and moved all colors to thier respective sections (e.g. annotation colors are now in[annotations]section, search hit colors are now in[search]section, etc.) for better organization and maintainability of the config file.
- Fix last page number loading
- Fix
[links]section causing pages to not render in non-link supported files - Fix page stride when zooming in DJVU files
- Fix zoom locking on the center of the viewport instead of the actual location
- Fix user shortcuts fighting with default shortcuts
- Fix zoom jumping to different page after zooming in/out.
- Fix annotation comment tooltip going off screen
- Fix color setting in the wrong format (ARGB instead of RGBA)
- Fix not able to save after adding comment
- Fix search results not clearing when searching for empty string
- Fix
-p,--pagecommand line argument not working - Fix non-exsistent files trying to be opened
- Fix document reload causing unnecessary popup of message box saying it couldn't reload document
- Fix crash when reloading after file changes on disk
- Fix crash and infinite loop when trying to reload after file save
- Fix layout changing at runtime not working properly
- Fix crash due to zero image size in BOOK layout mode
- Fix memory leaks due to not freeing up the cloned MuPDF
fz_context - Fix
searchnot working because of recent changes to page text caching - Fix page getting cut off in layout modes other than BOOK
- Fix search navigation being all jumpy and causing head-ache (literally!)
- Fix SINGLE layout
- Fix LEFT_TO_RIGHT and TOP_TO_BOTTOM layout
- Fix highlighting crash due to context removal
- Fix split focus
- Fix
page_gotodialog defaulting to page number 1 instead of current page number - Fix
page_gotorequesting render even when the dialog is closed without input - Fix multi click text selection
- Implement batch searching for faster search result fetching as soon as few searches are encountered.
- Regex searching
- Book (two-page) layout
[layout] { mode = "book" } - Ability to select text across page boundaries in layout modes with multiple pages visible
- Visual Line Mode
- Added visual line mode for text selection that can be toggled with
visual_line_modecommand. In this mode, when you select a line of text, the selection will automatically extend to the beginning and end of the line, making it easier to select whole lines of text without having to precisely click at the start or end of the line. - Snaps when moving to different pages
- mouse click in visual line mode to select the line
- Added visual line mode for text selection that can be toggled with
- Ability to set marks to locations in the document (both local and global level). Local marks are marks that are local to the document, whereas global marks are associated with particular document and when called will switch focus and go to the mark location in that document.
mark_goto- Ask user for the mark key and go to the location if key is validmark_set- Ask user for key to set the mark (local mark key start with lowercase letter or word and global starts with uppercase)mark_delete- Ask user for the mark key to delete and delete if the key is valid
search_regex- Opens searchbar with regex enabledlayout_book- Book layout mode (Two-page layout)mouse_follows_focus- when enabled, the mouse will automatically move to the center of the focused view when switching focus between splits or portals. This is useful for users who want to keep their hands on the keyboard and avoid having to move mouse manually to the view they just focused.
[portal]enabled(bool) : Enable portal (ctrl + click on link behavior)respect_parent(bool): Close portal when the source view is closedborder_width(int): Width of the border around the view signifying that the view is a portal
- Don't pass QPointF and QRectF as const references as it's useless.
- Cache
fz_stext_page*(performance boost)
-
Renamed command:
portal_focus->portal- Commands that begun with
toggle_are renamed to just the action they do without the toggle prefix (e.g.toggle_command_palette->command_palette,toggle_fullscreen->fullscreen, etc.) because it's more intuitive to have the command name reflect the action it does rather than the implementation (i.e. whether it toggles or shows/hides explicitly)
-
startup_tabwidget is not enabled by default anymore
- Centralised
pickerwidget for bothoutlineandsearch highlights(and potentially other similar widgets in the future). This allows us to reuse the code for both features and also allows us to easily add new features that require a similar UI in the future. - Orderless, space-aware searching ability for pickers by default (e.g. "open file", "file open" both will match "file_open" command)
- Add recent files picker (command:
files_recent) to quickly access recently opened files - Per page dimension support (instead of using the dimensions of the first page for the entire document, which causes issues with documents that have pages of different sizes)
- New config option
[window]initial_size(array of 2 ints): Initial window size in pixels (width, height)
[rendering]antialiasing(bool): Enable/Disable antialiasing for rendering (default: true)text_antialiasing(bool): Enable/Disable antialiasing for text rendering (default: true)smooth_pixmap_transform(bool): Enable/Disable smooth pixmap transformation when scaling (default: true)
[behavior]preload_pages(int): Number of pages to preload before and after the current page for smoother navigation (default: 5)
[selection]copy_on_select(bool): Copies selection to clipboard when text is selected (default: false)
- Moved the tab split count to the beginning of the tab instead of it being near the close button of the tab
- Fix MessageBar's showMessage causing resizeEvent of GraphicsView causing re-rendering of displayed pages
- Make
text_cachean LRU cache to reduce memory usage on large documents (used for text searching) - Use page dimension cache (instead of repeatedely querying the document for dimension) for
toPDFSpaceandtoPixelSpacefunctions to improve performance when converting coordinates between PDF space and pixel space, especially for documents with many pages or varying page sizes. - Memory efficient QImage for page rendering and avoiding conversion to QPixmap. (Huge performance boost)
- Remove
[outline]and[search_highlight]sections from the config. - Rename
[overlays]to[picker]which is a more accurate name for what it does. - Add
[picker.keys]section for keybindings related to the picker navigation keys (which applies to all picker widgets like outline, search highlights, recent files, etc.) - Removed panel settings from
[outline]and[search_highlight]section as overlays are the only variant supported for now. - Removed
config_auto_reloadfrom[behavior]as it was never supported. - Removed
icc_color_profilefrom[rendering]as it was never supported.
yank->selection_copycancel_selection->selection_cancelreselect_last_selection->selection_lastfirst_page->page_firstlast_page->page_lastnext_page->page_nextprev_page->page_prevgoto_page->page_gotoprev_location->location_prevnext_location->location_nextclose_split->split_closefocus_split_left->split_focus_leftfocus_split_right->split_focus_rightfocus_split_up->split_focus_upfocus_split_down->split_focus_downclose_other_splits->split_close_othersfocus_portal->portal_focussave_session->session_savesave_as_session->session_save_asload_session->session_loadtext_select_mode->selection_mode_textregion_select_mode->selection_mode_regionopen_file_tab->file_open_tabopen_file_vsplit->file_open_vsplitopen_file_hsplit->file_open_hsplitopen_file_dwim->file_open_dwimclose_file->file_closereload->file_reloadencrypt->file_encryptsave->file_savesave_as->file_save_astab1->tab_1tab2->tab_2tab3->tab_3tab4->tab_4tab5->tab_5tab6->tab_6tab7->tab_7tab8->tab_8tab9->tab_9about->show_aboutoutline->picker_outlinehighlight_annot_search->picker_highlight_searchcommand_palette->toggle_command_palettetutorial_file->show_tutorial_fileshow_startup->show_startup_widgetfullscreen->toggle_fullscreenauto_resize->fit_autotext_highlight_current_selection->highlight_selection
reopen_last_closed_file- Reopens the recently closed file in a new tabcopy_page_image- Copy the current page as image to clipboardfile_decrypt- Decrypt the current PDF fileannot_popup_mode- Enter popup annotation creation modereshow_jump_marker- Reshow the jump marker at the current location (useful if it was hidden after timeout)
- Optimize
pageSceneAtPosfunction to use a more efficient way of finding the page at a given position, which should improve performance when clicking on links or navigating to specific locations in the document. - Maintain a vector for
LinkHintpointers for efficient access and management of link hints, which should improve performance when showing and hiding link hints. - Optimize
clearDocumentItemsfunction to efficiently clear all items related to a document when it's closed, which should improve performance and reduce memory usage when closing documents.
- Fix tabs not respecting the
tabs.positionconfig option - Fix for tab title not updated when closing split
- Fix for tab title not updated which changing current split focus
-
Ability to create portals:
- A portal is a view of the same document but viewing different page or location in the document. Portals are useful for referencing different parts of the same document side by side, for example when reading a research paper and wanting to view the references at the same time. (Ctrl + click on a link to open the target in a new portal)
-
Ability to move tabs with mouse drag and drop within the tab bar and detach to new window if dropped outside
-
Ability to split the view into multiple panes to view different pages of the same document (or different) side by side
-
Ability to focus split with direction
-
New flags for opening files in
vsplitorhsplitdirectly from the command line--vsplit- Open file in a vertically split pane--hsplit- Open file in a horizontally split pane
-
New config options for splits
[split]focus_follows_mouse(bool): Whether to focus split pane on mouse hoverdim_inactive(bool): Whether to dim inactive split panesdim_inactive_opacity(float, 0-1): Opacity level for dimming inactive panes (default: 0.5)
-
New commands for splits
split_horizontal- Split the current view horizontallysplit_vertical- Split the current view verticallyclose_split- Close the current split pane
focus_split_left,focus_split_right,focus_split_up,focus_split_down- Move focus between split panes in the specified direction (if no pane in that direction, do nothing)open_file_vsplit- Open a file in a vertically split paneopen_file_hsplit- Open a file in a horizontally split pane
-
New command for opening file
open_file_dwim- Open file with "Do What I Mean" behavior: if there's a tab open with no splits, open the file in new tab, if there's a tab open with splits, open the file in current split.
- Fix tab drop opening new window instead of moving tab when dropped within the same window
- Fix window focus changing the dimmed state of split panes
- Fix crashing on splitting with huge documents.
- Remove filepath hash to keep track of already opened files, instead use the file path directly which should fix many other issues related to file opening and session restore
- Fix session loading layout restoration to work with the new splits system
- Fix
open_file_dwimnot working properly in some cases - Fix callback not being called after file open in some cases (due to async file opening)
- Fix panel and tab not showing file info properly on file single file open
- Hide scrollbars when the entire document is visible in the viewport
- Fix not using config zoom factor
- Fit incorrect zoom on file open
- Fix rendering bug when there's no value for DPR set in the config
- Fix TabWidget logo font
- Fix zoom clamp range
- Removed
uitable in config and moved all options to their respective sections[ui.command_palette]->[command_palette][ui.scrollbars]->[scrollbars][ui.statusbar]->[statusbar][ui.tabs]->[tabs][ui.outline]->[outline][ui.search_highlight]->[search_highlight][ui.llm_widget]->[llm_widget][ui.overlays]->[overlays]
- Add support for other MuPDF compatible file types: EPUB, XPS, CBZ, MOBI, FB2, SVG
- New Commands
tab_move_left,tab_move_right- move tabs in the tabBar left/right
- History navigation improvements
- Forward/next-location history navigation with
next_location - Preserve link source/target locations so jump markers land correctly
- Forward/next-location history navigation with
- Add
--aboutcommand line argument to show about dialog
- Disable access to annotation mode when not in PDF file (for other file formats)
- Remove PDF word from the file properties window title
- Fix text selection context menu takes precedence over annotation highlights when both apply
- Fix scrollbar auto-hide timer ignoring configured hide timeout after mouse leave
- Fix recent files page restore to open the stored page without adding history entries
- Remove
close_filecommand as it was redundant withtab_close(which does the same thing) - Rename
bar_positiontolocationin[ui.tabs]
- Add ability to copy unformatted text (removes hyphenation and joins lines)
- Add delete annotations implementation when in
annot_select_mode - Increased rendering performance.
- Add
tutorial_filecommand to show a tutorial PDF file - Added
role.txtsystem prompts for the LLM - Implement LRU (Least Recently Used) cache for reduced memory usage
- Respect
behavior.cache_pagesconfig option for this
- Respect
- Add frame border around the overlay widgets
- Replace
setdprcommand withset_dpr. This command now opens a popup input dialog asking for the new Device Pixel Ratio (DPR) value. - Drag-drop file handling
- Hold
Shiftwhile dropping a file onto the main view to open in a new window
- Hold
- Improved Startup Page
goto_pagecommand now registers current location for history navigation back to the page from where the command was called.
- Page foreground and background color config option
[colors]page_foreground(RGBA hex value)page_background(RGBA hex value)
- Tab close commands
[keybindings]tabs_close_left- close all tabs to the left of the current tabtabs_close_right- close all tabs to the right of the current tabtabs_close_others- close all tabs except the current tab
- New options for tabs
[ui.tabs]- Lazy loading
lazy_load(bool) - loads only when switching to the tab (useful when loading lots of papers) - File path in tab
[ui.tabs]full_path- whether to show full path in the tab
- Lazy loading
- Overlay frame config
[ui.overlays]border- show border around overlay framesshadowtableenabled- toggle shadow on overlay framesblur_radius- shadow blur radius in pixelsoffset_x- horizontal shadow offsetoffset_y- vertical shadow offsetopacity- shadow opacity (0-255)
- Set optimization flag and CacheMode for QGraphicsView
- Colors are now stored as packed RGBA ints and parsed from hex config values
NOTE: You might have to change few things in the config
- Command
first_tab,last_tabrenamed totab_first,tab_last - Remove
Fit Nonefrom the fit menu - Moved
Auto Resizecheckbox to the view menu instead of fit menu
- Fix startup page layout
- Fix orderless completion not working in the command palette
- Rename startup tab to
Startup Page - Fix double free in document cleanup
- Fix link hover cursor change
- Fix link navigation when target page is not yet rendered
- Hide the command palette before executing the command
- Fix command pallette showing only set keybound commands
- Fix tab close commands not working as expected
- Fix cursor not changing when hovering over link
- Fix right click context menu on tabs
- Command palette orderless matching consider underscore as literal when entered.
- Cancel page rendering request when starting to scroll
- Placeholder page items are just upscale pixmaps to reduce cpu and memory usage
- Render visible pages instead of just reloading single page when file changes in disk
- Don't cache
fz_stext_page(very memory intensive) - LLM Widget
- Disable send button in the LLM widget when there's no query
- Message when provider server is not found to be running
- Fix scroll commands not triggering scrollbar visibility (for auto_hide = true)
- Fix document not reloading even when
[behavior.auto_reload]is set to true - Hide searchbar when the search term is empty
- Fix loading default config when error is found in config
- Fix highlights search overlay hiding after selecting entry
- Fix dodo not compiling without synctex
- Change color of selected annotations
- Allow editing popup annotations (also called text annotations)
- Visual feedback when hovering over popup annotation icons
- Statusbar config option
[ui.statusbar]visible(bool): Show/Hide statusbarpadding(array of 4 ints): Padding around the statusbar (top, right, bottom, left)show_session_name(bool): Show session name in statusbarfile_name_only(bool): Show only file name instead of full pathshow_file_info(bool): Show file info (size, number of pages) in statusbarshow_page_number(bool): Show current page number in statusbarshow_mode(bool): Show current mode (e.g. selection mode) in statusbarshow_progress(bool): Show reading progress in statusbar
- Percentage progress indicator in statusbar
- Fix rect annotation creation
- Fix popup annotation creation
-
Command palette improvements
- Sort commands alphabetically
- Right-align shortcuts and optionally hide them (
[ui.command_palette].show_shortcuts)
-
Overlay scrollbars: Scrollbars now appear as floating overlays that don't shift the layout
- Auto-hide after configurable timeout (default 1500ms)
- Scrollbars remain visible while dragging or hovering over them
- Scrollbars flash on zoom in/out/reset
- New config options in
[ui.scrollbars]:auto_hide(bool): Auto hide scrollbar when not in usesize(int): Scrollbar width/height in pixels (default: 12)hide_timeout(int): Milliseconds before hiding after inactivity (default: 1500)
-
Detach from terminal - By default dodo will now detach from the terminal when launched from a terminal. This can be disabled by using the
--foregroundcommand line argument. -
Add LLM support [OPTIONAL]
- LLM (Large Language Model) integration is entirely optional and can be disabled completely from the code by the compile flag
ENABLE_LLM_SUPPORT. - Integrate with local LLM models to provide AI-powered assistance
- Config options:
[llm]enabled(bool): Enable/Disable LLM assistancemodel_path(string): Path to the local LLM modeltemperature(float): Sampling temperature for response generationmax_tokens(int): Maximum tokens in the generated response
- LLM (Large Language Model) integration is entirely optional and can be disabled completely from the code by the compile flag
-
Region Selection context menu
- Right click context menu when in region selection mode
- Copy text in region to clipboard
- Copy region as image to clipboard
- Save region as image to file
- Open region as image externally
- Right click context menu when in region selection mode
- Fix scrollbar disappearing while actively dragging
- Fix scrollbar hiding when quickly changing scroll direction
- Fix scrollbar handle size not updating after zoom
- Add visual feedback to current keypress in the link hinting mode
- Hide non-matching link hints as keys are entered and dim the typed digits
- Fix config color parsing to treat 8-digit hex values as RGBA
- Add orderless, space-aware command palette search
-
Cross-window tab drag and drop: Tabs can now be dragged between windows or detached to create new windows.
-
Change cursor when selecting or highlighting text
-
Searchable text highlights
-
Outline widget and Search Highlight widget types - "dialog", "side_panel", "overlay" (configurable in settings)
- UI
[ui.outline]-type=<value>where value =dialog,side_panel,overlay[ui.search_highlight]-type=<value>where value =dialog,side_panel,overlay
- UI
-
Detection of non-link URL pdf object in the PDF and making them clickable links (optional, configurable in settings)
- [ui.links]
detect_urls- Enable/Disable non-link URL detection and linkificationurl_regex- Custom regex for URL detection (default is a standard URL regex)
- [ui.links]
-
New options in
[behavior]:cache_pages(int): Maximum number of pages to keep cached per document. Default is20.always_open_in_new_window(bool): If true, files will always open in a new window instead of a new tab. Default isfalse.
- Remove stray return causing panel update issues
- Fix prompting for password protected documents
- Fix session loading not opening files properly - files now load correctly with their saved state (page, zoom, fit mode, invert color)
- Fix session page restoration using wrong page index (1-indexed vs 0-indexed)
- Fix early return in
openFileFinishedcallback that prevented the callback from being executed for documents with outlines - Fix context menu not showing at the right position
- Fix fit width not working properly in some cases
- Fix startup Page widget not respecting fit mode from config
- Fix scrolling to specific position and center it in the viewport
- Fix zoom changing the viewport position unexpectedly
- Show highlight search overlay properly
- Fix double memory free crash on exit when there's more than one tab
- Show information if no outline is present in the document instead of empty outline panel
- Fix crash when rendering link/annotation items from background threads
- Add runtime layout switching
- Link hinting mode for keyboard link navigation
- Updated organized configuration settings (check config.toml)
- Fix first page and last page offset in LEFT_TO_RIGHT and TOP_TO_BOTTOM layouts
- Make scrollbar handle transparent to allow search hits marker visibility
- Show placeholder page when pages are loading
- Use queue for managing threads while rendering instead of spawning threads for each render request
- Make asynchronous to avoid UI blocking on large documents
- Add min and max zoom levels
- Add Link Keyboard hinting mode
- Show loading spinner when loading huge documents
- Add rotation support
- Fix annotation deleting
- Fix panel name modified status not updating properly
- Fix annotation select at point and rectangle selection
- Fix highlight annotation rendering issues
- Fix highlight annotation coordinate mismatch
- Fix invert color not reloading already visible pages
- Fix LEFT_TO_RIGHT layout not showing vertical scrollbar
- Fix link clicking
- Fix context menu positioning
- Search hits marker on the scrollbar
- Config option to enable/disable search hits marker on scrollbar
- UI
search_hits_on_scrollbar
- UI
- Search is now smart case by default (i.e. case insensitive unless uppercase letters are used in the search query)
- Search Bar improvements
- Show only icons and not text in the search bar buttons
- Close file in tab
- Preload next and previous pages for faster navigation (configurable in settings)
- Rendering
preload_adjacent_pagesnum_preloaded_pages
- Rendering
- Layouts
- Single Page
- Left to Right
- Top to Bottom
- Config option to set default layout on file open
- UI
layout- values:single,left-to-right,top-to-bottom
- UI
- Click on links not working properly in some cases
- Fix navigation from menu
- Fix synctex to work with new rendering system
- Significantly improved rendering performance by optimizing memory copying from MuPDF to Qt
- Fix go back history not working properly
- Single page layout issues
- Link item deletion
- Page navigation
- History navigation issues
- Switch from single view rendering to tile based rendering like sane PDF viewers
- Huge rewrite of the rendering system
- Asynchronous rendering
- Improved performance
- Fix annotation rendering issues
- Fix annotation position issues on zoom and pan
- Zoom render debounce to improve performance
- Make fit window, fit width, fit height work properly with the new debounce logic
- Add popup annotation menu item
- Edit last pages widget disable when no entries exist
- Don't render highlight annotations as it's done by MuPDF
- Merge highlight annotations on overlapping areas
- Remove padding around the document view
- Fix installation script
- Fix build issues
- Fix .desktop file installation
- Fix skinny statusbar
- Fix panel file name display (absolute vs relative path)
- Fix session file overwriting without prompt
- Fix session path to file
- Add session button to panel
- Fix session button label
- Fix synctex not working after reloading file
- Update session files if in session on application exit
- Fix loading session opening second window on launch
- Implement document reloading on external changes
- Remove command bar
- Implement clean search bar UI
- Undo/Redo support for annotations
- Rect annotations
- Text highlight annotations
- Delete annotations
- Multi-click text selection (double, triple, quadruple click for word, line, paragraph)
- Page rotation (clockwise and counter-clockwise)
- Editable page number in panel (click to edit and navigate)
- Tab navigation keybindings (tab_next, tab_prev, tab1-tab9)
- Config options:
- Behavior
undo_limit- Maximum number of undo operations to keep
- Behavior
- Jump marker fading animation fix
- Fix unsaved changes being asked multiple times
- Centralized unsaved handling
- Fix copy text popup when no text is selected
- Wonky selection handling
- Fix scaling problem in single monitor systems
- Multi-monitor user defined scaling support
- Region select mode
- Copy text from selected region to clipboard
- Copy selected region as image to clipboard
- Save selected region as jpeg/png etc. image
- Open selected region externally
- Image right click context menu
- Copy image to clipboard
- Save image as jpeg/png/psd
- Open image externally
- Display Pixel Ratio user config option (fix blurry text on high DPI screens)
- Outline widget as a sidebar option
- Outline widget page numbers displayed properly
- Outline hierarchy search support
- Config options:
- UI
outline_as_side_paneloutline_panel_widthlink_hint_size
- Rendering
dpr
- UI
- Popup annotations improved
- Fix buggy selection behavior after clicking
- Fix blurry text on high DPI screens
- Fix popup annotation not deleting properly
- Fix drag and drop not opening files
- Popup Annotation support
- Page navigation menu disable unintended buttons
- Fix startup tab on launch with files
- Vim-like search in commandbar
- Goto page from commandbar
- Fix goto page
- Fix link clicking mouse release event
- Fix recent files addition
- Fix panel and other actions updating on tab switching
- Tabs support
- Sessions support
- Bug fixes
- Page visit history
- Link visit
- http/https links
- Page links
- XYZ links
- Browse links implemented (URL)
- Basic rectangle annotations
- Search
- Table of Contents
- File properties
- Keyboard link navigation
- Render
- Navigation
- Panel
