Previous: Abstract Display Functions, Up: Abstract Display

38.18.2 Abstract Display Example

Here is a simple example using functions of the ewoc package to implement a “color components display”, an area in a buffer that represents a vector of three integers (itself representing a 24-bit RGB value) in various ways.

     (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 " (sample text) "))
           (insert "Color\t: "
                   (propertize samp 'face
                               `(foreground-color . ,cstr))
                   (propertize samp 'face
                               `(background-color . ,cstr))
                   "\n"))))
     
     (defun colorcomp (color)
       "Allow fiddling with COLOR in a new buffer.
     The buffer is in Color Components mode."
       (interactive "sColor (name or #RGB or #RRGGBB): ")
       (when (string= "" color)
         (setq color "green"))
       (unless (color-values color)
         (error "No such color: %S" color))
       (switch-to-buffer
        (generate-new-buffer (format "originally: %s" color)))
       (kill-all-local-variables)
       (setq major-mode 'colorcomp-mode
             mode-name "Color Components")
       (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
                                "\nColor Components\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)))

This example can be extended to be a “color selection widget” (in other words, the controller part of the “model/view/controller” design paradigm) by defining commands to modify colorcomp-data and to “finish” the selection process, and a keymap to tie it all together conveniently.

     (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 ()
       "Copy the color components into the kill ring and kill the buffer.
     The string is formatted #RRGGBB (hash followed by six hex digits)."
       (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
           (let ((m (make-sparse-keymap)))
             (suppress-keymap m)
             (define-key m "i" 'colorcomp-R-less)
             (define-key m "o" 'colorcomp-R-more)
             (define-key m "k" 'colorcomp-G-less)
             (define-key m "l" 'colorcomp-G-more)
             (define-key m "," 'colorcomp-B-less)
             (define-key m "." 'colorcomp-B-more)
             (define-key m " " 'colorcomp-copy-as-kill-and-exit)
             m))

Note that we never modify the data in each node, which is fixed when the ewoc is created to be either nil or an index into the vector colorcomp-data, the actual color components.