79 Commits
Author SHA1 Message Date
DJ 29537f64ab fix(regionSelector): monitor buttons follow left-to-right layout order
Replace the manual monitorOrder config array (a debugging artifact from a
temporarily rearranged setup) with automatic sorting by Hyprland layout
position (ascending x, ties by y). The list is rebuilt on every overlay
open, screen hotplug, and shortcut re-trigger, with refreshMonitors() and
an unpopulated-monitor (lastIpcObject) fallback to ShellScreen position.
Removes the regex JSONC parse path and the monitorOrder key from the
config schema and defaults.
2026-07-05 11:14:21 -04:00
DJ 5344908036 fix(regionSelector): cross-monitor captures honor initiator's Crop mode and action
The captureMonitorRequested relay now carries the initiating screen's
captureMode and action; the selector stashes both before the
targetMonitorCapture pulse and the target adopts them before capturing:
- Crop mode on screen A now opens B's crop editor instead of an
  instant snip when A clicks B's monitor button
- cross-monitor right-click Edit was silently broken (target replayed
  with session-default Copy; its null mouseButton skipped the override)
- sessionReset now re-pushes action alongside selectionMode, since the
  adoption breaks the target's action binding
2026-07-05 09:58:22 -04:00
DJ 1d785947de fix(snipCommands): Copy never clobbers the clipboard on failed capture
buildCopyCommand stages the crop to a file and gates wl-copy + the
success notification on magick's exit status AND a non-empty file:
- piping magick straight into wl-copy cleared the clipboard and fired
  a false 'Copied to clipboard' whenever the crop failed or was empty
- the save branch's [ -f ] check passed on tee-created empty files
- pre-clean prevents a stale .crop.png from a killed run passing the gate
- wl-copy failure now notifies ('Copy failed' / 'Saved, copy failed')
- cleanup is ;-chained so the source screenshot never leaks on failure
2026-07-05 09:40:52 -04:00
DJ 2fa907c451 fix(regionSelector): freehand loop closed on its start pixel draws, not clicks
- circleDrawn predicate (Freehand && points.length > 1) excluded from the
  click branch, so zero-displacement closed loops reach the circle branch
- points cleared at press: stale samples from a cancelled grab could
  otherwise flip the new click/draw routing
- toolbar mode tabs ignore mid-drag swaps, matching the R/C key guards
2026-07-05 09:22:16 -04:00
DJ 304ee48a03 fix(regionSelector): edge-straddling targeting + gated hit-testing + clamp trim
- targetedRegionValid() uses a dedicated flag, not a >= 0 sign check, so
  windows/layers straddling the monitor's left/top edge are selectable
- updateTargetedRegion gates each region-list hit-test by the same
  enable* flag as its highlight repeater (no invisible-region selection)
- clampRegionToScreen trims overhang from the region's original far edge
  instead of sliding the rect on-screen at full size over foreign content
- snip() re-validates size post-clamp (trim can zero edge-touching rects)
2026-07-05 01:25:08 -04:00
DJ ef737f5992 fix(regionSelector): Freehand->Rect auto-swap fires at Crop entry, not exit
The swap in onCaptureModeChanged read isCropMode - a derived binding
that may not have re-evaluated inside the handler - so it skipped at
entry (stale false) and fired at exit (stale true), leaving the tab
oval on Freehand for the whole Crop session. Read captureMode directly.

Also hardened while diagnosing: ToolbarTabBar indicator binds its edge
targets directly to children[currentIndex] (drops the property Item
hop), and gains an interactive property so callers dim via opacity
instead of enabled: false.
2026-07-05 00:40:17 -04:00
DJ 3bbfdbb6bf feat(regionSelector): Crop implies Rect - auto-swap Freehand on entry
Entering Crop while Freehand is active swaps selection to Rect; the R
key and the Rect/Freehand tabs are inert while Crop is on. Leaving Crop
keeps Rect (no restore); already-Rect swaps are no-ops.
2026-07-04 23:56:46 -04:00
DJ 0ac5c4fca8 fix(regionSelector): drop freehand mask in Crop mode - true-shape is Instant-only
The crop editor is a rectangle tool; a polygon mask its handles cannot
reshape only confuses. A freehand loop in Crop still seeds the editor
with its bounding box, but confirm captures the adjusted rect.
2026-07-04 23:52:05 -04:00
DJ 510446e499 feat(regionSelector): freehand true-shape capture, R/Space keys, single-owner mode state
- fix: capture-mode state desync (6-press C cycle, inverted tab display).
  selectionMode/captureMode now have a single owner (RegionSelection);
  the toolbar receives them as read-only bindings and emits *Selected
  request signals on tab clicks - no more bidirectional Synchronizer +
  currentIndex write-back storms. captureMode is int (same-value writes
  no longer emit change signals).
- feat: freehand (ex-Circle) true-shape capture - a polygon mask makes
  pixels outside the drawn loop transparent (OCR flattens onto white;
  recording stays rectangular). Mask survives the crop editor: confirm
  captures loop intersected with the adjusted rect.
- feat: circle/freehand selection works in Crop mode (loop bounding box
  seeds the editor); Rect/Freehand tabs inert only while editing.
- feat: R toggles Rect/Freehand; Space confirms the crop editor;
  'Circle' tab relabeled Freehand (config keys keep circle names).
- docs: MANUAL, wiki, CONFIG_README, CHANGELOG updated.
2026-07-04 23:47:21 -04:00
DJ 285a7b4e5f feat(regionSelector): add Crop Mode with adjustable-handle editor
CaptureMode { Instant, Crop } toggled by C or Instant/Crop toolbar tabs.
In Crop, release seeds an 8-handle + interior-move editor over the
retained frame (min-size and screen clamps); Enter or the confirm FAB
dispatches through the existing snip(), Esc cancels back to draw.
Action-agnostic: screenshots and recording both confirm through it.
New config: regionSelector.crop.minSize / handleSize.
2026-07-04 22:47:52 -04:00
DJ fc69fe6642 fix(regionSelector): add click/drag dead-zone so jittery clicks select the hovered region
Sub-dragThreshold (default 6px, per-axis) press-to-release movements now
classify as clicks: whole hovered window/region -> Copy/Edit per button.
Resolve the hovered target at press so zero-motion clicks have a target,
and dismiss cleanly when a sub-threshold gesture has no valid target
(previously snipped a tiny sliver past snip()'s <=0 guard). Circle mode
keeps zero tolerance via the binding-site ternary.

New config key: regionSelector.dragThreshold (0 disables; negatives
clamp to 0).
2026-07-04 20:24:03 -04:00
DJ 18ee7a5644 chore(release): 1.6.0
satty default annotation tool, hypr-lens/hl wrappers, and selection
overlay rounding that matches Hyprland's decoration:rounding.
2026-06-06 14:43:15 -04:00
DJ 9bbfa60208 docs(changelog): add Unreleased section for satty, wrappers, and rounding 2026-06-06 14:43:15 -04:00
DJ 470bab70ec feat(installer): add hypr-lens/hl wrappers and satty integration
Complete the satty annotation feature on the install side:
- Install hypr-lens + hl wrapper scripts (detach on launch, sync for IPC)
  and remove them on uninstall
- Add satty as an optional dependency and bundle defaults/satty.toml into
  the config dir (never touches ~/.config/satty)
- Update README/MANUAL to use the hypr-lens/hl commands instead of raw
  'qs --path ...'
- Add dev-update.sh helper for syncing scripts + shell.qml integration
2026-06-06 14:43:15 -04:00
DJ 1e01b0ab5c docs(config): drop 'killall quickshell' tip; config hot-reloads
The JSON config is watched via FileView { watchChanges: true } and reloads
live, so no restart is needed. The old tip was also harmful: 'killall
quickshell' kills every quickshell instance (including the DMS desktop
shell), and 'quickshell &' relaunches the default config, not hypr-lens.
Mirror hypr-overview's wording.
2026-06-06 14:43:15 -04:00
DJ a0f3b14039 feat(regionSelector): adopt satty as default annotation tool
Replace the swappy edit flow with satty (preferred), driven by a bundled
config (satty -c ~/.config/hypr-lens/satty.toml) plus per-mode CLI flags,
so the edit action saves to the hypr-lens dir, copies to the clipboard,
and discards on Escape natively - with no XDG_CONFIG_HOME override, so GTK
theming stays native. Falls back to a bare swappy invocation when satty is
disabled or not installed (regionSelector.annotation.useSatty, default
true). satty owns its own notifications. Mirrors end-4's ScreenshotAction
tool toggle with the default flipped to satty.

Note: installer wiring (satty optional dep + bundled-config install) lives
in hypr-lens-install.sh, left unstaged here to avoid bundling unrelated
in-progress edits to that file.
2026-06-06 14:43:15 -04:00
DJ 501fec3560 fix(regionSelector): save swappy-edited screenshots to hypr-lens dir
Capture swappy's final surface via `swappy -f - -o -` (stdout on exit)
and route it through hypr-lens's own clipboard/disk handling instead of
relying on swappy's Save button, which only writes to swappy's global
save_dir (~/Desktop) and is unreachable from hypr-lens. Respects
copyAlsoSaves: clipboard always, disk file only when enabled. Removes
the fragile wl-paste hack; cleans up the empty output file on failed
saves. Diagnosed in swappy-save-button-investigation.md.
2026-06-05 22:47:25 -04:00
DJ fc8cca1f22 feat(regionSelector): match selection overlay rounding to Hyprland
Source decoration:rounding live from HyprlandData over hyprctl IPC and
bind the window/layer selection-overlay radius to it (raw 1:1), so the
overlay corners trace real window corners. Falls back to 18 on query
failure. Removes the now-unused Appearance.rounding.windowRounding.
2026-06-05 22:22:30 -04:00
DJ 472152801f fix(common): add missing appearance properties and fix Revealer content detection
Add default values for sizes.elevationMargin, font.family.numbers, and
font.variableAxes.main to prevent undefined property errors when these
aren't specified in user config.

Fix Revealer widget using contentChildren instead of children, which
caused content items to not be detected properly.
2025-12-31 19:07:20 -05:00
DJ 114f029638 fix(regionSelector): wrap notify command in subshell braces
Fix shell command execution in snip-to-clipboard pipeline where the
notify-send command could fail silently due to improper command grouping.
2025-12-31 18:55:25 -05:00
DJ 9eb5fb32e1 Add related projects to README.md 2025-12-20 21:31:44 -05:00
DJ ab7c3e643c fix(appearance): correctly load matugen colors from JSON file
- Add QtCore import for StandardPaths API
- Fix defaultMatugenPath to use writableLocation() and strip file:// prefix
- Change matugenFile.text to text() (it's a function, not property)
- Add onFileChanged: reload() for live color updates when wallpaper changes

Previously, hypr-lens was always using hardcoded fallback colors because
FileView.text was being accessed as a property instead of called as a
function, resulting in empty content.
2025-12-20 21:22:10 -05:00
DJ aa839445dd docs(readme): center badges in header
Wrap badge images in centered paragraph to align with the rest of the
header elements (logo, title, tagline, nav links).
2025-12-20 17:14:10 -05:00
DJ f79b8ff409 Update README.md 2025-12-20 17:02:58 -05:00
DJ c216760a9a Update README.md 2025-12-20 17:02:46 -05:00
DJ 4ac27e475c Update README.md 2025-12-20 17:01:28 -05:00
DJ a331c67fca docs(changelog): add v1.5.0 - developer setup and contributor docs 2025-12-20 12:53:51 -05:00
DJ 7b25fa0442 docs(readme): add Development link to nav 2025-12-20 12:37:03 -05:00
DJ 3446e3f619 chore: add dev-setup.sh for contributor workflow
Creates symlinks from install dirs to repo for live editing.
Also adds wiki/ to .gitignore for local wiki editing.
2025-12-20 12:36:48 -05:00
DJ e9f6a22c6e refactor(installer): remove dev-only symlink handling
Symlink detection was only relevant for development workflow.
Regular users always get files copied - this cleans up the code path.
2025-12-20 12:36:36 -05:00
DJ f4c3d5e7d3 fix(installer): handle symlinked install directories gracefully
Add symlink detection to prevent "same file" errors when QML modules
or scripts directories are symlinked to the repo (common for dev setups).

- Add is_symlink_to_source() helper function
- Skip copy operations when destination symlinks to source
- Show appropriate success message for symlinked directories
- Apply check to both install and update mode operations
2025-12-20 00:05:58 -05:00
DJ d02a2bbf99 Update CHANGELOG.md 2025-12-19 19:41:03 -05:00
DJ a1326070e2 fix(notifications): proper notify-send execution and consistent behavior
- Add & disown to notify-send for proper background execution
- Clean notification format: action as title, path as body
- Swappy now respects copyAlsoSaves setting (saves clipboard if true)
- Remove auto-save from swappy; clipboard-focused by default
- Consistent messaging: "Copied to clipboard" vs "Copied & saved"
2025-12-19 19:40:37 -05:00
DJ eb1c95dde1 docs(changelog): update notification feature with swappy watcher details 2025-12-19 18:42:48 -05:00
DJ 9dcd6fe4c4 feat(screenshots): instant swappy notifications with file watcher
- Add background file watcher that monitors for saves while swappy is open
- Notifications fire instantly when user clicks Save (not after close)
- Supports multiple saves - each triggers a notification
- Consistent notification format: "hypr-lens" title with message in body
- Watcher polls file mtime every 0.3s with minimal overhead
- Properly cleans up watcher process when swappy closes
2025-12-19 18:42:14 -05:00
DJ e3e9f4d134 feat(screenshots): add notifications for copy and save operations
Visual feedback via notify-send when screenshots are:
- Copied to clipboard
- Saved to disk (shows full path)
- Failed to save (error notification)

Swappy edit mode shows notification only when file is saved,
silent when user cancels or uses swappy's clipboard copy.
2025-12-19 18:30:20 -05:00
DJ 71a3c3ecdd docs(changelog): add code quality note to 1.4.0 2025-12-19 18:30:02 -05:00
DJ 52b5a1e5a4 refactor: extract save path helpers and remove obsolete JSONC handling
- Extract resolveSavePath() and buildSaveSetup() in SnipCommands.qml
  to eliminate duplicate save path logic between Copy and Edit commands
- Remove unnecessary sed JSONC comment stripping from record.sh since
  config format is now plain JSON
2025-12-19 18:20:28 -05:00
DJ 43ead1c508 docs(changelog): reorder versions to reverse chronological
Versions now display newest-first (1.4.0 → 1.0.0) following Keep a
Changelog convention. Added consistent separators between entries.
2025-12-19 18:16:33 -05:00
DJ c616efa0cc fix(screenshots): save to configured path with tilde expansion
Fixes #1 - Screenshots now properly save to disk when savePath is configured.

Changes:
- Changed config format from JSONC to JSON for reliable parsing
- Added tilde (~) expansion for all save paths
- Edit mode (swappy) now saves to configured savePath via -o flag
- Default paths: ~/Pictures/hypr-lens, ~/Videos/hypr-lens
- Added copyAlsoSaves option for users who want Copy to also save
- Copy mode (left-click) now clipboard-only by default
- Updated documentation and changelog

Closes #1
2025-12-19 18:12:08 -05:00
DJ 9c97ec1364 fix(region-selector): add missing services import for MonitorButton tooltip
- Add import "../../services" to access Translation singleton
- Simplify tooltip text to static string for clarity
2025-12-16 02:52:35 -05:00
DJ c53a7976b4 docs: clarify compatibility for other distros
Add note that NixOS, Fedora, and other distros can manually install
by handling dependencies themselves. The QML components are distro-agnostic,
only the installer script is Arch-centric.
2025-12-16 01:14:52 -05:00
DJ a1138a57c8 feat(region-selector): add right-click to edit on monitor buttons
Add ability to right-click monitor buttons in the region selector toolbar
to capture the full monitor and open swappy for editing, mirroring the
existing right-click behavior for region selection.

Changes:
- MonitorButton: add editRequested signal and altAction handler
- OptionsToolbar: add editFullMonitor signal propagation
- RegionSelection: add editFullMonitor() function, fix action override logic

Refactors included:
- Use enum keys in commandBuilders for self-documenting code
- Extract circle bounding box calculation to RegionDragState
2025-12-16 00:45:05 -05:00
sleepingsage 17734941d1 Update issue templates 2025-12-14 00:01:30 -05:00
DJ c0abd5416b Update README.md 2025-12-09 20:21:08 -05:00
DJ 5c0b94eb58 Update README.md 2025-12-09 20:20:50 -05:00
DJ db30259587 Create CHANGELOG.md 2025-12-09 20:19:52 -05:00
DJ 2ddce4faa7 Update hypr-lens.svg 2025-12-09 15:45:27 -05:00
DJ 1fd38208f2 Create hypr-lens.svg 2025-12-09 15:09:42 -05:00
DJ 9780607878 chore: remove video assets from tracking (now on GitHub CDN) 2025-12-08 23:11:33 -05:00
DJ ba7052f748 Update .gitignore 2025-12-08 23:10:29 -05:00
DJ e69dd045fa Update .gitignore 2025-12-08 23:09:40 -05:00
DJ b69324f510 fix(assets): re-encode demo videos to H.264 for GitHub compatibility
HEVC/H.265 videos don't play on GitHub. Re-encoded to H.264 with
significant size reduction (7MB -> 432KB for largest file).
2025-12-08 23:05:58 -05:00
DJ 4570886402 Changed to web friendly name 2025-12-08 22:58:08 -05:00
DJ 72f351c655 Fixed video format 2025-12-08 22:55:42 -05:00
DJ 50ff4807b2 Update Timeline 1.mov 2025-12-08 22:55:42 -05:00
DJ c2eea3fbfe Add video demo assets 2025-12-08 22:34:57 -05:00
DJ 5e6beeb01b refactor(region-selector): extract utilities and reduce duplication
- Create ActionConfig.qml singleton for centralized action metadata
- Create RegionUtils.js with parsing, clamping, and sorting utilities
- Extract MonitorButton.qml component for reusability
- Consolidate 5 action methods into single openWithAction()
- Replace switch statements with table-driven command building
- Improve control animations using State/Transition pattern

Reduces ~70 lines of duplicated code while improving maintainability.
2025-12-08 21:45:24 -05:00
DJ 2dc90c4e18 feat(region-selector): add one-click monitor capture buttons
Add monitor buttons (DP-1, DP-2, etc.) to the region selector toolbar
for instant full-screen capture without drag selection.

- Add monitor buttons alongside Rect/Circle selection modes
- Support screenshot, record, and recordWithSound modes (not OCR/Search)
- Add configurable button order via `monitorOrder` in config
- Support cross-monitor capture from any toolbar
- Use regex extraction to read config from JSONC files
2025-12-08 21:27:30 -05:00
DJ d9f590700e docs(readme): add image search workflow note 2025-12-08 17:38:18 -05:00
DJ 66e22f0471 docs(readme): add wiki link to navigation 2025-12-08 17:16:56 -05:00
DJ d815ae6299 docs(security): add disclaimer about line number accuracy over time 2025-12-08 17:05:29 -05:00
DJ 7beac8fd67 docs(readme): add Security section with link to SECURITY.md 2025-12-08 17:02:48 -05:00
DJ fb40fd1060 docs: add SECURITY.md transparency document
Security audit document explaining what the installer does:
- TL;DR table with quick security overview
- Detailed breakdown with line number references
- Package manager operations explained (sudo is optional)
- Safety features documented
- Verification commands for users to audit themselves
2025-12-08 17:01:26 -05:00
DJ df8ee9bd2f docs(readme): add Arch Linux compatibility notice 2025-12-08 16:50:05 -05:00
DJ 8f83328352 chore: pre-public cleanup
- Remove startup console.log debug messages
- Remove TODO comments (unfinished/vague)
- Remove commented-out dead code
2025-12-08 16:47:47 -05:00
DJ 84fae02e74 refactor(installer): add invalid input handling to integration recovery 2025-12-08 16:39:47 -05:00
DJ e5857bc938 fix(installer): detect and recover missing shell integration in update mode
When running --update, now actively checks if shell.qml integration was
lost (e.g., after dotfiles update) and offers:
1. Auto-integrate with backup
2. Show manual instructions
3. Skip

Previously only showed a passive warning after completion.
2025-12-08 16:38:20 -05:00
DJ bdc5455fce docs(readme): note refactoring in project description 2025-12-08 15:59:05 -05:00
DJ 7e3998ae57 docs(readme): add auto-install tip and polish update section
- Note that installer auto-detects and installs missing dependencies
- Add git pull step to update workflow with explanation
- Fix repository URLs to correct username
2025-12-08 15:55:19 -05:00
DJ 371178688a Update README.md 2025-12-08 15:52:49 -05:00
DJ 239ec5bce0 Create hyprland.svg 2025-12-08 15:46:00 -05:00
DJ 40ad37a62f chore: add gitignore
Ignore patterns for:
- Python bytecode and virtual environments
- QML cache files
- IDE/editor configs
- Development artifacts (backups, local docs)
- Credentials and secrets
2025-12-08 15:07:44 -05:00
DJ 4b783a2030 docs: add project documentation
- README with installation, usage, and configuration guide
- MANUAL with detailed IPC commands and advanced usage
2025-12-08 15:07:44 -05:00
DJ 7de9fd3f2b chore: add default configuration
JSONC config template with documented options for:
- Appearance settings (matugen theming, ripple effects)
- Screenshot and recording save paths
- OCR and image search preferences
- Region selector behavior (window detection, opacity)
- Selection tool customization (rect/circle modes)
2025-12-08 15:07:44 -05:00
DJ 888f8b67f0 feat: add installer and keybinds
Automated installer with:
- Dry-run mode for previewing changes
- QML module deployment to ~/.config/quickshell/
- Script installation to ~/.local/share/hypr-lens/
- Optional Python venv setup for OpenCV
- Auto-integration into existing quickshell configs
- Uninstall support

Includes example Hyprland keybinds for all features.
2025-12-08 15:07:44 -05:00
DJ 5d88afc46c feat: add helper scripts
- OpenCV-based content region detection (Python)
- Virtual environment setup for Python dependencies
- Screen recording wrapper for wf-recorder
2025-12-08 15:07:44 -05:00
DJ ff6618d4e7 feat: add core QML region selector
QuickShell-based UI for screen capture with:
- Region selector overlay with window/layer detection
- Material Design widgets (ripple buttons, tooltips, toolbar)
- Material shapes library for rounded polygon rendering
- Services for Hyprland data, app search, and i18n
- Global state management and configuration system
2025-12-08 15:07:44 -05:00
sleepingsage 58bbff8b7e Initial commit 2025-12-08 14:55:11 -05:00