Skip to content

Instantly share code, notes, and snippets.

@jdtsmith
Last active September 9, 2023 18:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jdtsmith/73f386a48bff5475f21b995f433d9579 to your computer and use it in GitHub Desktop.
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
(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")))))
@jdtsmith
Copy link
Author

jdtsmith commented Sep 9, 2023

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:

image

@jdtsmith
Copy link
Author

jdtsmith commented Sep 9, 2023

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