Вот простой пример использования функций пакета ewoc для реализации отображения цветовых компонент — области в буфере, которая представляет вектор из трёх целых чисел (сам по себе представляющий 24-битное значение RGB) различными способами.
(setq colorcomp-ewoc nil
colorcomp-data nil
colorcomp-mode-map nil
colorcomp-labels ["Red" "Green" "Blue"])
(defun colorcomp-pp (data)
(if data
(let ((comp (aref colorcomp-data data)))
(insert (aref colorcomp-labels data) "\t: #x"
(format "%02X" comp) " "
(make-string (ash comp -2) ?#) "\n"))
(let ((cstr (format "#%02X%02X%02X"
(aref colorcomp-data 0)
(aref colorcomp-data 1)
(aref colorcomp-data 2)))
(samp " (пример текста) "))
(insert "Цвет\t: "
(propertize samp 'face
`(foreground-color . ,cstr))
(propertize samp 'face
`(background-color . ,cstr))
"\n"))))
(defun colorcomp (color)
"Разрешить возиться с COLOR в новом буфере.
Буфер находится в режиме Color Components."
(interactive "sЦвет (имя или #RGB или #RRGGBB): ")
(when (string= "" color)
(setq color "green"))
(unless (color-values color)
(error "Нет такого цвета: %S" color))
(switch-to-buffer
(generate-new-buffer (format "изначально: %s" color)))
(kill-all-local-variables)
(setq major-mode 'colorcomp-mode
mode-name "Цветовые компоненты")
(use-local-map colorcomp-mode-map)
(erase-buffer)
(buffer-disable-undo)
(let ((data (apply 'vector (mapcar (lambda (n) (ash n -8))
(color-values color))))
(ewoc (ewoc-create 'colorcomp-pp
"\nЦветовые компоненты\n\n"
(substitute-command-keys
"\n\\{colorcomp-mode-map}"))))
(set (make-local-variable 'colorcomp-data) data)
(set (make-local-variable 'colorcomp-ewoc) ewoc)
(ewoc-enter-last ewoc 0)
(ewoc-enter-last ewoc 1)
(ewoc-enter-last ewoc 2)
(ewoc-enter-last ewoc nil)))
Этот пример можно расширить до виджета выбора цвета (другими словами,
части “контроллера” парадигмы проектирования “модель–представление–контроллер”),
определив команды для изменения colorcomp-data
и завершения процесса выбора, а также клавиатурную карту для удобного связывания
всего вместе.
(defun colorcomp-mod (index limit delta)
(let ((cur (aref colorcomp-data index)))
(unless (= limit cur)
(aset colorcomp-data index (+ cur delta)))
(ewoc-invalidate
colorcomp-ewoc
(ewoc-nth colorcomp-ewoc index)
(ewoc-nth colorcomp-ewoc -1))))
(defun colorcomp-R-more () (interactive) (colorcomp-mod 0 255 1))
(defun colorcomp-G-more () (interactive) (colorcomp-mod 1 255 1))
(defun colorcomp-B-more () (interactive) (colorcomp-mod 2 255 1))
(defun colorcomp-R-less () (interactive) (colorcomp-mod 0 0 -1))
(defun colorcomp-G-less () (interactive) (colorcomp-mod 1 0 -1))
(defun colorcomp-B-less () (interactive) (colorcomp-mod 2 0 -1))
(defun colorcomp-copy-as-kill-and-exit ()
"Скопировать цветовые компоненты в кольцо убийств и убить буфер.
Строка форматируется как #RRGGBB (решётка, за которой следуют шесть шестнадцатеричных цифр)."
(interactive)
(kill-new (format "#%02X%02X%02X"
(aref colorcomp-data 0)
(aref colorcomp-data 1)
(aref colorcomp-data 2)))
(kill-buffer nil))
(setq colorcomp-mode-map
(define-keymap :suppress t
"i" 'colorcomp-R-less
"o" 'colorcomp-R-more
"k" 'colorcomp-G-less
"l" 'colorcomp-G-more
"," 'colorcomp-B-less
"." 'colorcomp-B-more
"SPC" 'colorcomp-copy-as-kill-and-exit))
Обратите внимание, что мы никогда не изменяем данные в каждом узле; они фиксируются при
создании ewoc и равны либо nil, либо индексу в векторе
colorcomp-data, который содержит собственно цветовые компоненты.