refactor: text-scale-mode per-buffer zoom (×1.5/krok), UI stays at base size

This commit is contained in:
2026-02-22 15:26:14 +01:00
parent 196ebacd47
commit 292f257bfc
2 changed files with 68 additions and 53 deletions

119
config.el
View File

@@ -698,79 +698,96 @@ Skips past the TODO keyword and optional priority indicator [#A]."
;;; ============================================================ ;;; ============================================================
;;; ACCESSIBILITY — GLOBAL TEXT SCALING (SPC z) ;;; ACCESSIBILITY — GLOBAL TEXT SCALING (SPC z)
;;; ============================================================ ;;; ============================================================
;; Uses `default-text-scale` for true global scaling (face remapping on all ;; Uses per-buffer `text-scale-mode' applied to ALL buffers simultaneously.
;; frames). Unlike `text-scale-mode` this affects every buffer, minibuffer, ;; Unlike `default-text-scale', this scales ONLY buffer text.
;; popup, which-key, corfu, and transient menu uniformly. ;; Modeline, minibuffer, which-key, corfu popups stay at base size
;; and remain fully visible and usable even at very high zoom levels.
;;
;; Step: ×1.5 per step (multiplicative). From 14pt base:
;; +1 → ×1.5 ≈ 21pt +2 → ×2.25 ≈ 32pt
;; +3 → ×3.4 ≈ 47pt +4 → ×5.1 ≈ 71pt
;; +5 → ×7.6 ≈ 106pt
;;
;; SPC z + / SPC z = zoom in
;; SPC z - zoom out
;; SPC z 0 reset to default (saves for restore)
;; SPC z z restore previous zoom
(use-package! default-text-scale (setq text-scale-mode-step 1.5)
:config
(setq default-text-scale-amount 10)) ; 10 units = 1pt
(defvar my/zoom-total-delta 0 (defvar my/zoom-steps 0
"Cumulative face-height delta applied by global zoom (in face units).") "Current global zoom step count. 0 = default, positive = bigger.")
(defvar my/zoom-saved-delta nil (defvar my/zoom-saved-steps nil
"Saved delta before last reset, used by `my/zoom-restore'.") "Step count saved before last `my/zoom-reset', for restore.")
(defvar my/zoom-min-height 80 (defun my/zoom--apply-all (steps)
"Minimum face height (in units, 80 = 8pt). Zoom out stops here.") "Apply text-scale of STEPS to every live buffer."
(dolist (buf (buffer-list))
(when (buffer-live-p buf)
(with-current-buffer buf
(text-scale-set steps)))))
(defun my/zoom--current-height () (defun my/zoom--auto-apply ()
"Return the current default face height including zoom delta." "Apply current zoom to newly opened/switched buffers."
(face-attribute 'default :height)) (unless (= my/zoom-steps 0)
(text-scale-set my/zoom-steps)))
(defun my/zoom--msg () ;; Hook: apply zoom when a new buffer gets a major mode (covers find-file,
"Display current effective font size in pt." ;; new scratch buffers, magit, org-agenda, help, etc.)
(let ((h (my/zoom--current-height))) (add-hook 'after-change-major-mode-hook #'my/zoom--auto-apply)
(message "Zoom: %s pt (delta %+d)"
(/ h 10)
my/zoom-total-delta)))
(defun my/zoom-in () (defun my/zoom-in ()
"Increase global font size by 1 pt." "Zoom in one step (×1.5) across all buffers."
(interactive) (interactive)
(default-text-scale-increase) (cl-incf my/zoom-steps)
(cl-incf my/zoom-total-delta default-text-scale-amount) (my/zoom--apply-all my/zoom-steps)
(my/zoom--msg)) (message "Zoom +%d (×%.2f ≈%dpt)"
my/zoom-steps
(expt text-scale-mode-step my/zoom-steps)
(round (* 14 (expt text-scale-mode-step my/zoom-steps)))))
(defun my/zoom-out () (defun my/zoom-out ()
"Decrease global font size by 1 pt (respects minimum)." "Zoom out one step (÷1.5) across all buffers."
(interactive) (interactive)
(let ((new-height (- (my/zoom--current-height) default-text-scale-amount))) (cl-decf my/zoom-steps)
(if (< new-height my/zoom-min-height) (my/zoom--apply-all my/zoom-steps)
(message "Zoom: already at minimum (%d pt)" (/ (my/zoom--current-height) 10)) (message "Zoom %d (×%.2f ≈%dpt)"
(default-text-scale-decrease) my/zoom-steps
(cl-decf my/zoom-total-delta default-text-scale-amount) (expt text-scale-mode-step my/zoom-steps)
(my/zoom--msg)))) (round (* 14 (expt text-scale-mode-step my/zoom-steps)))))
(defun my/zoom-reset () (defun my/zoom-reset ()
"Reset zoom to default size. Saves current delta for restore." "Reset all buffers to default text size. Saves current step for restore."
(interactive) (interactive)
(if (= my/zoom-total-delta 0) (if (= my/zoom-steps 0)
(message "Zoom: already at default size") (message "Zoom: already at default")
(setq my/zoom-saved-delta my/zoom-total-delta) (setq my/zoom-saved-steps my/zoom-steps)
(default-text-scale-reset) (my/zoom--apply-all 0)
(setq my/zoom-total-delta 0) (setq my/zoom-steps 0)
(message "Zoom: reset to default (saved %+d for restore)" (message "Zoom reset to default (was %+d — SPC z z to restore)"
my/zoom-saved-delta))) my/zoom-saved-steps)))
(defun my/zoom-restore () (defun my/zoom-restore ()
"Restore the zoom level saved before last reset." "Restore zoom level saved before last reset."
(interactive) (interactive)
(if (null my/zoom-saved-delta) (if (null my/zoom-saved-steps)
(message "Zoom: nothing to restore") (message "Zoom: nothing to restore")
(default-text-scale-adjust my/zoom-saved-delta) (my/zoom--apply-all my/zoom-saved-steps)
(setq my/zoom-total-delta my/zoom-saved-delta) (setq my/zoom-steps my/zoom-saved-steps
(setq my/zoom-saved-delta nil) my/zoom-saved-steps nil)
(my/zoom--msg))) (message "Zoom restored: %+d (×%.2f ≈%dpt)"
my/zoom-steps
(expt text-scale-mode-step my/zoom-steps)
(round (* 14 (expt text-scale-mode-step my/zoom-steps))))))
(map! :leader (map! :leader
(:prefix ("z" . "zoom") (:prefix ("z" . "zoom")
:desc "Zoom in" "+" #'my/zoom-in :desc "Zoom in (×1.5/krok)" "+" #'my/zoom-in
:desc "Zoom in" "=" #'my/zoom-in :desc "Zoom in (×1.5/krok)" "=" #'my/zoom-in
:desc "Zoom out" "-" #'my/zoom-out :desc "Zoom out (÷1.5/krok)" "-" #'my/zoom-out
:desc "Reset zoom" "0" #'my/zoom-reset :desc "Reset na výchozí" "0" #'my/zoom-reset
:desc "Restore zoom" "z" #'my/zoom-restore)) :desc "Restore předchozí zoom" "z" #'my/zoom-restore))
;;; ============================================================ ;;; ============================================================

View File

@@ -74,5 +74,3 @@
(package! org-pandoc-import (package! org-pandoc-import
:recipe (:host github :repo "tecosaur/org-pandoc-import")) :recipe (:host github :repo "tecosaur/org-pandoc-import"))
;; Global text scaling for accessibility
(package! default-text-scale)