config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

textsize.el (6224B)


      1 ;;; textsize.el --- Configure frame text size automatically  -*- lexical-binding: t; -*-
      2 ;;
      3 ;; Copyright (C) James Ferguson
      4 ;;
      5 ;; Author: James Ferguson <james@faff.org>
      6 ;; Version: 3.0
      7 ;; Package-Requires: ((emacs "26.1"))
      8 ;; Keywords: convenience
      9 ;; URL: https://github.com/WJCFerguson/textsize
     10 ;;
     11 ;; This file is not part of GNU Emacs.
     12 ;;
     13 ;;; License:
     14 ;;
     15 ;; SPDX-License-Identifier: GPL-3.0-or-later
     16 ;;
     17 ;;; Commentary:
     18 ;;
     19 ;; This package automatically calculates and adjusts the default text size for
     20 ;; the size and pixel pitch of the display.
     21 ;;
     22 ;; Hooks to perform the adjustment automatically are set up by enabling
     23 ;; `textsize-mode' on initialization.  e.g.:
     24 ;;
     25 ;;     (use-package textsize
     26 ;;       :init (textsize-mode))
     27 ;;
     28 ;; Alternatively, the adjustment may be manually triggered by calling
     29 ;; `textsize-fix-frame'.
     30 ;;
     31 ;; You will first want to adjust `textsize-default-points' if the default size
     32 ;; does not match your preferences.
     33 ;;
     34 ;; The calculation is very simplistic but should be adaptable to many scenarios
     35 ;; and may be modified using the `-thresholds' customizations below.
     36 ;;
     37 ;; You may wish to bind keys for transient manual adjustment of the current
     38 ;; frame with `textsize-increment', `textsize-decrement', and `textsize-reset'
     39 ;;
     40 ;;; Code:
     41 
     42 
     43 ;; =============================================================================
     44 (defgroup textsize nil
     45   "Automatically adjusting frame text sizes to suit the current display."
     46   :group 'convenience)
     47 
     48 (defcustom textsize-default-points 15
     49   "The baseline font point size, to then be adjusted with -thresholds values.
     50 
     51 Some fonts at least appear to render better at point sizes that
     52 are multiples of 3."
     53   :type 'integer)
     54 
     55 (defcustom textsize-monitor-size-thresholds '((0 . -3) (350 . 0) (500 . 3))
     56   "Point size offsets from the maximum monitor dimension in mm.
     57 
     58 List of pairs of (monitor-size-in-mm . font-point-offset).
     59 
     60 The 2nd value (cdr) of the final cell encountered where the 1st
     61 value (car) is <= the monitor size from
     62 `textsize--monitor-size-mm', will be used as a font point offset.
     63 Thresholds should therefore be sorted in rising order.
     64 
     65 The default of ((0 . -3) (350 . 0) (500 . 3)) will shrink the
     66 text for anything smaller than 350mm, and enlarge it for >500mm"
     67   :type '(list (cons integer integer)))
     68 
     69 (defcustom textsize-pixel-pitch-thresholds '((0 . 3) (0.12 . 0) (0.18 . -3) (0.25 . -6))
     70   "List of (px-pitch-threshold . font-point-offset).
     71 
     72 As with `textsize-monitor-size-thresholds', an offset will be
     73 selected from the monitor's pixel pitch in mm, from `textsize--pixel-pitch'."
     74   :type '(list (cons integer integer)))
     75 
     76 ;; =============================================================================
     77 (defun textsize--monitor-size-mm (frame)
     78   "Return the max dimension of FRAME's monitor in mm."
     79   (apply #'max (frame-monitor-attribute 'mm-size frame)))
     80 
     81 
     82 (defun textsize--monitor-size-px (frame)
     83   "Return the max dimension of FRAME's monitor in pixels."
     84   (apply #'max (cddr (frame-monitor-attribute 'geometry frame))))
     85 
     86 
     87 (defun textsize--pixel-pitch (frame)
     88   "Calculate the pixel pitch for FRAME in mm."
     89   ;; On a rotated monitor, px geom is rotated but size is not, so use
     90   ;; max dimension of each.
     91   (/ (float (textsize--monitor-size-mm frame))
     92      (textsize--monitor-size-px frame)))
     93 
     94 
     95 (defun textsize--threshold-offset (threshold-list val)
     96   "Find the offset for VAL in THRESHOLD-LIST."
     97   (let ((result 0))
     98     (dolist (threshold threshold-list)
     99       (when (>= val (car threshold))
    100         (setq result (cdr threshold))))
    101     result))
    102 
    103 (defun textsize--point-size (frame)
    104   "Return the point size to use for this FRAME."
    105   (+ textsize-default-points
    106      ;; manual adjustment:
    107      (or (frame-parameter frame 'textsize-manual-adjustment) 0)
    108      ;; pixel pitch adjustment:
    109      (textsize--threshold-offset textsize-pixel-pitch-thresholds
    110                                  (textsize--pixel-pitch frame))
    111      ;; monitor size in mm adjustment:
    112      (textsize--threshold-offset textsize-monitor-size-thresholds
    113                                  (textsize--monitor-size-mm frame))))
    114 
    115 (defun textsize--window-size-change (window-or-frame)
    116   "Defun for `window-size-change-functions' to fix WINDOW-OR-FRAME text size."
    117   (when (and (framep window-or-frame) (frame-size-changed-p window-or-frame))
    118     (textsize-fix-frame window-or-frame)))
    119 
    120 ;;;###autoload
    121 (defun textsize-modify-manual-adjust (frame offset)
    122   "Adjust FRAME's font-point adjustment by OFFSET persistently.
    123 
    124 Add a custom fixed offset to the textsize point size calculation.
    125 
    126 If OFFSET is nil, reset adjustment to zero."
    127   (set-frame-parameter
    128    frame
    129    'textsize-manual-adjustment
    130    (if offset
    131        (+ offset (or (frame-parameter frame 'textsize-manual-adjustment) 0))
    132      0))
    133   (message "Setting default font to %s points" (textsize--point-size frame))
    134   (textsize-fix-frame frame))
    135 
    136 ;;;###autoload
    137 (defun textsize-increment ()
    138   "Increment the current frame's automatic text size."
    139   (interactive)
    140   (textsize-modify-manual-adjust (selected-frame) 1))
    141 
    142 ;;;###autoload
    143 (defun textsize-decrement ()
    144   "Decrement the current frame's automatic text size."
    145   (interactive)
    146   (textsize-modify-manual-adjust (selected-frame) -1))
    147 
    148 ;;;###autoload
    149 (defun textsize-reset ()
    150   "Reset the adjustment on the current frame's automatic text size."
    151   (interactive)
    152   (textsize-modify-manual-adjust (selected-frame) nil))
    153 
    154 ;;;###autoload
    155 (defun textsize-fix-frame (&optional frame)
    156   "Set the default text size appropriately for FRAME display."
    157   (interactive)
    158   (when (display-graphic-p)
    159     (let* ((frame (or frame (selected-frame))))
    160       (set-frame-parameter frame
    161                            'font
    162                            (format "%s-%d"
    163                                    (face-attribute 'default :family)
    164                                    (textsize--point-size frame))))))
    165 
    166 ;;;###autoload
    167 (define-minor-mode
    168   textsize-mode
    169   "Adjusts the default text size for the size and pixel pitch of the display."
    170   :global t
    171   :group 'textsize
    172   (if textsize-mode
    173       (add-to-list 'window-size-change-functions #'textsize--window-size-change)
    174     (delete #'textsize--window-size-change window-size-change-functions)))
    175 
    176 (provide 'textsize)
    177 ;;; textsize.el ends here