From 8f3e46c22dbf81b2e1fbc833975193206aa879da Mon Sep 17 00:00:00 2001 From: Daneel Date: Sun, 22 Feb 2026 20:54:09 +0100 Subject: [PATCH] feat: split-screen magnifier + readable preset + centered-cursor-mode --- config.el | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 130 insertions(+), 5 deletions(-) diff --git a/config.el b/config.el index ee44f22..501f0ea 100644 --- a/config.el +++ b/config.el @@ -33,12 +33,21 @@ (setq which-key-idle-delay 0.8 which-key-idle-secondary-delay 0.05) -;; Centered cursor mode — disabled: conflicts with macOS Zoom focus follower +;; Centered cursor mode — safe with macOS Zoom set to "Follow mouse cursor" +;; (NOT "Follow keyboard focus" — that causes viewport jumping) (use-package! centered-cursor-mode :config - (setq ccm-vpos-init 0.5) - ;; (global-centered-cursor-mode +1) ; uncomment to enable - ) + (setq ccm-vpos-init 0.5 ; cursor uprostřed obrazovky + ccm-step-size 2 ; plynulejší scroll + ccm-recenter-at-end-of-file t) + ;; Vypnout v terminálu a speciálních módech + (define-globalized-minor-mode my/global-ccm + centered-cursor-mode + (lambda () + (unless (memq major-mode '(vterm-mode eshell-mode term-mode + treemacs-mode pdf-view-mode)) + (centered-cursor-mode 1)))) + (my/global-ccm +1)) ;;; ============================================================ @@ -804,6 +813,118 @@ Keeps the status bar and tab bar fully visible at any zoom level.") (setq my/zoom-steps my/zoom-saved-steps my/zoom-saved-steps nil))) +(defun my/zoom-readable () + "Přepne na čitelný zoom preset (32pt ≈ step +2)." + (interactive) + (setq my/zoom-steps 2) + (my/zoom--apply my/zoom-steps)) + + +;;; ============================================================ +;;; ACCESSIBILITY — SPLIT-SCREEN MAGNIFIER (SPC z m) +;;; ============================================================ +;; Dual-view: hlavní okno (normální font) + magnified okno (zvětšený). +;; Indirect buffer sdílí obsah, ale má vlastní text-scale. +;; Cursor pozice se synchronizuje přes post-command-hook. + +(defvar my/mag--buffer nil "Indirect buffer pro magnified view.") +(defvar my/mag--source nil "Source buffer pro magnifier.") +(defvar my/mag--active nil "Je magnifier aktivní?") +(defvar my/mag--zoom-level 4 + "Zoom level pro magnified view (text-scale steps). 4 ≈ 2.3× zvětšení.") + +(defun my/mag-toggle () + "Toggle split-screen magnifier. Vytvoří/zruší zvětšené okno vpravo." + (interactive) + (if my/mag--active + (my/mag--disable) + (my/mag--enable))) + +(defun my/mag--enable () + "Zapni magnified split view pro aktuální buffer." + (let* ((src (current-buffer)) + (mag-name (format "*mag:%s*" (buffer-name src))) + (mag (or (get-buffer mag-name) + (make-indirect-buffer src mag-name t)))) + (setq my/mag--buffer mag + my/mag--source src + my/mag--active t) + (with-current-buffer mag + (text-scale-set my/mag--zoom-level) + (setq-local display-line-numbers nil)) + (split-window-right (floor (* 0.6 (window-width)))) + (save-selected-window + (other-window 1) + (switch-to-buffer mag) + (goto-char (with-current-buffer src (point))) + (recenter)) + (add-hook 'post-command-hook #'my/mag--sync) + (add-hook 'kill-buffer-hook #'my/mag--on-kill nil t) + (message "Magnifier ON (zoom +%d)" my/mag--zoom-level))) + +(defun my/mag--disable () + "Vypni magnifier a zavři magnified okno." + (remove-hook 'post-command-hook #'my/mag--sync) + (when (and my/mag--buffer (buffer-live-p my/mag--buffer)) + (when-let ((win (get-buffer-window my/mag--buffer))) + (delete-window win)) + (kill-buffer my/mag--buffer)) + (setq my/mag--buffer nil + my/mag--source nil + my/mag--active nil) + (message "Magnifier OFF")) + +(defun my/mag--on-kill () + "Cleanup když se zavře source buffer." + (when (and my/mag--active + (eq (current-buffer) my/mag--source)) + (my/mag--disable))) + +(defun my/mag--sync () + "Synchronizuj pozici kurzoru v magnified view." + (when (and my/mag--active + my/mag--buffer + (buffer-live-p my/mag--buffer) + my/mag--source + (eq (current-buffer) my/mag--source)) + (let ((pos (point))) + (when-let ((win (get-buffer-window my/mag--buffer))) + (with-selected-window win + (goto-char pos) + (recenter)))))) + +(defun my/mag--follow-buffer () + "Přepni magnifier na nový buffer když uživatel změní aktivní buffer." + (when (and my/mag--active + (not (eq (current-buffer) my/mag--source)) + (not (minibufferp)) + (not (string-prefix-p " " (buffer-name))) + (not (string-prefix-p "*mag:" (buffer-name)))) + (my/mag--disable) + (my/mag--enable))) + +(add-hook 'window-selection-change-functions + (lambda (_frame) (when my/mag--active + (run-with-idle-timer 0.1 nil #'my/mag--follow-buffer)))) + +(defun my/mag-zoom-in () + "Zvětši zoom magnified view." + (interactive) + (cl-incf my/mag--zoom-level) + (when (and my/mag--buffer (buffer-live-p my/mag--buffer)) + (with-current-buffer my/mag--buffer + (text-scale-set my/mag--zoom-level)) + (message "Mag zoom: +%d" my/mag--zoom-level))) + +(defun my/mag-zoom-out () + "Zmenši zoom magnified view." + (interactive) + (cl-decf my/mag--zoom-level) + (when (and my/mag--buffer (buffer-live-p my/mag--buffer)) + (with-current-buffer my/mag--buffer + (text-scale-set my/mag--zoom-level)) + (message "Mag zoom: +%d" my/mag--zoom-level))) + ;; --------------- keybindings --------------- (map! :leader @@ -812,7 +933,11 @@ Keeps the status bar and tab bar fully visible at any zoom level.") :desc "Zoom in (×1.5)" "=" #'my/zoom-in :desc "Zoom out (÷1.5)" "-" #'my/zoom-out :desc "Reset na výchozí" "0" #'my/zoom-reset - :desc "Restore předchozí" "z" #'my/zoom-restore)) + :desc "Restore předchozí" "z" #'my/zoom-restore + :desc "Readable (32pt)" "r" #'my/zoom-readable + :desc "Toggle magnifier" "m" #'my/mag-toggle + :desc "Mag zoom in" "M" #'my/mag-zoom-in + :desc "Mag zoom out" "N" #'my/mag-zoom-out)) ;;; ============================================================