From 14d1dd072cc3f2968d4079463b8cad9ca647ecbe Mon Sep 17 00:00:00 2001 From: Daneel Date: Sun, 22 Feb 2026 15:30:22 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20true=20screen=20magnifier=20=E2=80=94?= =?UTF-8?q?=20global=20default=20face=20+=20pinned=20modeline/minibuffer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.el | 117 +++++++++++++++++++++++++++++------------------------- 1 file changed, 62 insertions(+), 55 deletions(-) diff --git a/config.el b/config.el index 62ee3f9..1f09d52 100644 --- a/config.el +++ b/config.el @@ -698,96 +698,103 @@ Skips past the TODO keyword and optional priority indicator [#A]." ;;; ============================================================ ;;; ACCESSIBILITY — GLOBAL TEXT SCALING (SPC z) ;;; ============================================================ -;; Uses per-buffer `text-scale-mode' applied to ALL buffers simultaneously. -;; Unlike `default-text-scale', this scales ONLY buffer text. -;; Modeline, minibuffer, which-key, corfu popups stay at base size -;; and remain fully visible and usable even at very high zoom levels. +;; True screen magnifier: scales the global `default' face (all buffers, +;; help windows, doom menus, org-agenda, magit — everything). ;; -;; 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 +;; Modeline + minibuffer are PINNED to base size after every zoom so they +;; stay fully visible and usable regardless of zoom level. +;; which-key shows in the minibuffer area → also stays readable. ;; -;; 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 +;; Step: ×1.5 per step (multiplicative, not additive). From 14pt base: +;; +1 ≈ 21pt +2 ≈ 32pt +3 ≈ 47pt +;; +4 ≈ 71pt +5 ≈ 106pt +6 ≈ 159pt +;; +;; SPC z + / = zoom in +;; SPC z - zoom out +;; SPC z 0 reset to default (saves level for restore) +;; SPC z z restore zoom before last reset -(setq text-scale-mode-step 1.5) +;; Base height: captured once at startup (reflects doom-font :size). +;; Fallback to 140 = 14pt if face-attribute returns non-integer. +(defvar my/zoom-base-height 140 + "Default face height before any zoom. Captured at Doom init.") (defvar my/zoom-steps 0 - "Current global zoom step count. 0 = default, positive = bigger.") + "Current zoom step count. 0 = default.") (defvar my/zoom-saved-steps nil - "Step count saved before last `my/zoom-reset', for restore.") + "Step count saved before last `my/zoom-reset', for `my/zoom-restore'.") -(defun my/zoom--apply-all (steps) - "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))))) +;; Faces that must stay at base height (do not scale with text). +;; These form the fixed UI chrome: status bar, minibuffer, tab bar. +(defvar my/zoom-pinned-faces + '(mode-line mode-line-inactive mode-line-active + minibuffer-prompt header-line + tab-bar tab-bar-tab tab-bar-tab-inactive) + "Faces pinned to `my/zoom-base-height' after every zoom operation.") -(defun my/zoom--auto-apply () - "Apply current zoom to newly opened/switched buffers." - (unless (= my/zoom-steps 0) - (text-scale-set my/zoom-steps))) +(defun my/zoom-pin-ui () + "Set pinned UI faces to base height so they don't scale with text." + (dolist (face my/zoom-pinned-faces) + (when (facep face) + (set-face-attribute face nil :height my/zoom-base-height)))) -;; Hook: apply zoom when a new buffer gets a major mode (covers find-file, -;; new scratch buffers, magit, org-agenda, help, etc.) -(add-hook 'after-change-major-mode-hook #'my/zoom--auto-apply) +(defun my/zoom--apply (steps) + "Set global default face to base × 1.5^STEPS and re-pin UI faces." + (let ((new-h (max 80 (round (* my/zoom-base-height (expt 1.5 steps)))))) + (set-face-attribute 'default nil :height new-h) + (my/zoom-pin-ui) + (message "Zoom %+d ×%.2f ≈%dpt" + steps (expt 1.5 steps) (/ new-h 10)))) + +;; Capture base height after Doom finishes font setup. +(add-hook 'doom-after-init-hook + (lambda () + (let ((h (face-attribute 'default :height nil t))) + (when (and (integerp h) (> h 0)) + (setq my/zoom-base-height h))))) + +;; Re-pin UI faces after any theme reload (Doom resets faces on theme change). +(add-hook 'doom-load-theme-hook #'my/zoom-pin-ui) (defun my/zoom-in () - "Zoom in one step (×1.5) across all buffers." + "Zoom in one step (×1.5) — all buffers, help, menus, everything." (interactive) (cl-incf my/zoom-steps) - (my/zoom--apply-all my/zoom-steps) - (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))))) + (my/zoom--apply my/zoom-steps)) (defun my/zoom-out () - "Zoom out one step (÷1.5) across all buffers." + "Zoom out one step (÷1.5) — all buffers." (interactive) (cl-decf my/zoom-steps) - (my/zoom--apply-all my/zoom-steps) - (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))))) + (my/zoom--apply my/zoom-steps)) (defun my/zoom-reset () - "Reset all buffers to default text size. Saves current step for restore." + "Reset to default font size. Saves current level so SPC z z can restore." (interactive) (if (= my/zoom-steps 0) (message "Zoom: already at default") (setq my/zoom-saved-steps my/zoom-steps) - (my/zoom--apply-all 0) + (my/zoom--apply 0) (setq my/zoom-steps 0) - (message "Zoom reset to default (was %+d — SPC z z to restore)" - my/zoom-saved-steps))) + (message "Zoom reset (SPC z z to restore %+d)" my/zoom-saved-steps))) (defun my/zoom-restore () "Restore zoom level saved before last reset." (interactive) (if (null my/zoom-saved-steps) (message "Zoom: nothing to restore") - (my/zoom--apply-all my/zoom-saved-steps) + (my/zoom--apply my/zoom-saved-steps) (setq my/zoom-steps my/zoom-saved-steps - my/zoom-saved-steps nil) - (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)))))) + my/zoom-saved-steps nil))) (map! :leader (:prefix ("z" . "zoom") - :desc "Zoom in (×1.5/krok)" "+" #'my/zoom-in - :desc "Zoom in (×1.5/krok)" "=" #'my/zoom-in - :desc "Zoom out (÷1.5/krok)" "-" #'my/zoom-out - :desc "Reset na výchozí" "0" #'my/zoom-reset - :desc "Restore předchozí zoom" "z" #'my/zoom-restore)) + :desc "Zoom in (×1.5)" "+" #'my/zoom-in + :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)) ;;; ============================================================