Last active
September 9, 2023 18:06
-
-
Save jdtsmith/73f386a48bff5475f21b995f433d9579 to your computer and use it in GitHub Desktop.
Using Emacs `:stipple` face attribute for drawing bars and other pixel-level features
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(let ((buf (get-buffer-create "*stipple-box*"))) | |
(switch-to-buffer-other-window buf) | |
(cl-flet ((srot (s r) (concat (substring s (- r)) (substring s 0 (- r))))) | |
(let* ((bar-width 0.3) | |
(w (window-font-width)) | |
(h (window-font-height)) | |
(rot (indent-bars--stipple-rot w)) | |
(bsz (round (* bar-width w))) | |
(vrot (mod (cadr (window-edges nil t nil t)) h)) | |
(pad (make-string (- h bsz) ?\s)) | |
(vpat-top (srot (concat pad (make-string bsz ?.)) vrot)) | |
(vpat-bot (srot (concat (make-string bsz ?.) pad) vrot)) | |
(vbar-left (indent-bars--stipple w h rot bar-width 0 "." nil)) | |
(vbar-right (indent-bars--stipple w h rot bar-width (- 1 bar-width) "." nil)) | |
(vbar-left-string (propertize " " 'face `(:stipple ,vbar-left))) | |
(vbar-right-string (propertize " " 'face `(:stipple ,vbar-right))) | |
(row-string (concat vbar-left-string (make-string 28 ?\s) vbar-right-string)) | |
(hbar-top (indent-bars--stipple w h rot 1. 0. vpat-top nil)) | |
(hbar-bot (indent-bars--stipple w h rot 1. 0. vpat-bot nil)) | |
(hbar-top-string (propertize (make-string 30 ?\s) 'face `(:stipple ,hbar-top))) | |
(hbar-bot-string (propertize (make-string 30 ?\s) 'face `(:stipple ,hbar-bot)))) | |
(erase-buffer) | |
(insert (concat "\n " hbar-top-string "\n")) | |
(dotimes (_ 10) (insert " " row-string "\n")) | |
(insert " " vbar-left-string " This box is drawn " vbar-right-string "\n") | |
(insert " " vbar-left-string " with :stipple " vbar-right-string "\n") | |
(dotimes (_ 10) (insert " " row-string "\n")) | |
(insert " " row-string) | |
(insert (concat "\n " hbar-bot-string "\n"))))) |
Some important points about :stipple
:
- Each stipple is a repeating bitmap, which starts at the absolute pixel position of the frame's top-left pixel (behind the margin and fringe) and repeats down and right infinitely.
- The basic idea is to make stipple patterns of the same width and height as characters.
- Setting a face containing a
:stipple
attribute on some visible characters simply "open up" a window onto that fixed stipple pattern. - You therefore have to rotate the bitmap byte pattern appropriately to get it to line up. This can be automated on window and text size changes, as indent-bars does.
- For drawing horizontal lines, you need to perform a similar rotation of the stipple list, based on the vertical window pixel offset into the frame.
window-edges
can tell you these pixel offsets. - This idea only works if line width and height are constant, so images, emoji, variable width/height fonts, etc. will make patterns unstable.
You can easily create a few faces that have :stipple
set, apply them to various characters in a buffer, and use face-remapping-alist
to quickly update colors, etc. In principle with enough care you could draw anything with a stipple pattern.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This small proof-of-concept shows the use of stipple face attributes to draw both horizontal and vertical lines. It uses functions from indent-bars. Here's how it looks: