diff --git a/config.el b/config.el index 55b2e1f..fbfbd32 100644 --- a/config.el +++ b/config.el @@ -674,6 +674,84 @@ Skips past the TODO keyword and optional priority indicator [#A]." (advice-add 'dtk-initialize :after #'my/dtk-apply-global-default-rate)) +;;; ============================================================ +;;; ACCESSIBILITY — GLOBAL TEXT SCALING (SPC z) +;;; ============================================================ +;; Uses `default-text-scale` for true global scaling (face remapping on all +;; frames). Unlike `text-scale-mode` this affects every buffer, minibuffer, +;; popup, which-key, corfu, and transient menu uniformly. + +(use-package! default-text-scale + :config + (setq default-text-scale-amount 10)) ; 10 units = 1pt + +(defvar my/zoom-total-delta 0 + "Cumulative face-height delta applied by global zoom (in face units).") + +(defvar my/zoom-saved-delta nil + "Saved delta before last reset, used by `my/zoom-restore'.") + +(defvar my/zoom-min-height 80 + "Minimum face height (in units, 80 = 8pt). Zoom out stops here.") + +(defun my/zoom--current-height () + "Return the current default face height including zoom delta." + (face-attribute 'default :height)) + +(defun my/zoom--msg () + "Display current effective font size in pt." + (let ((h (my/zoom--current-height))) + (message "Zoom: %s pt (delta %+d)" + (/ h 10) + my/zoom-total-delta))) + +(defun my/zoom-in () + "Increase global font size by 1 pt." + (interactive) + (default-text-scale-increase) + (cl-incf my/zoom-total-delta default-text-scale-amount) + (my/zoom--msg)) + +(defun my/zoom-out () + "Decrease global font size by 1 pt (respects minimum)." + (interactive) + (let ((new-height (- (my/zoom--current-height) default-text-scale-amount))) + (if (< new-height my/zoom-min-height) + (message "Zoom: already at minimum (%d pt)" (/ (my/zoom--current-height) 10)) + (default-text-scale-decrease) + (cl-decf my/zoom-total-delta default-text-scale-amount) + (my/zoom--msg)))) + +(defun my/zoom-reset () + "Reset zoom to default size. Saves current delta for restore." + (interactive) + (if (= my/zoom-total-delta 0) + (message "Zoom: already at default size") + (setq my/zoom-saved-delta my/zoom-total-delta) + (default-text-scale-reset) + (setq my/zoom-total-delta 0) + (message "Zoom: reset to default (saved %+d for restore)" + my/zoom-saved-delta))) + +(defun my/zoom-restore () + "Restore the zoom level saved before last reset." + (interactive) + (if (null my/zoom-saved-delta) + (message "Zoom: nothing to restore") + (default-text-scale-increment my/zoom-saved-delta) + (setq my/zoom-total-delta my/zoom-saved-delta) + (setq my/zoom-saved-delta nil) + (my/zoom--msg))) + +(map! :leader + (:prefix ("z" . "zoom") + :desc "Zoom in" "+" #'my/zoom-in + :desc "Zoom in" "=" #'my/zoom-in + :desc "Zoom out" "-" #'my/zoom-out + :desc "Reset zoom" "0" #'my/zoom-reset + :desc "Restore zoom" "z" #'my/zoom-restore)) + + ;;; ============================================================ ;;; KEYBINDINGS ;;; ============================================================ diff --git a/packages.el b/packages.el index b24920f..9da0ab8 100644 --- a/packages.el +++ b/packages.el @@ -73,3 +73,6 @@ ;; pandoc (package! org-pandoc-import :recipe (:host github :repo "tecosaur/org-pandoc-import")) + +;; Global text scaling for accessibility +(package! default-text-scale)