diff options
| author | Juri Linkov | 2010-06-14 19:03:04 +0300 |
|---|---|---|
| committer | Juri Linkov | 2010-06-14 19:03:04 +0300 |
| commit | f0bf7c8e5525fb4f964530c17399c3c987a79927 (patch) | |
| tree | 2f55e221c7ddd0268d6541b5b4ee318c8a372b51 | |
| parent | c42fe9a55d2356f509ea38e6de6fcec95fd6ac63 (diff) | |
| download | emacs-f0bf7c8e5525fb4f964530c17399c3c987a79927.tar.gz emacs-f0bf7c8e5525fb4f964530c17399c3c987a79927.zip | |
Add sort option `list-colors-sort'. (Bug#6332)
* lisp/facemenu.el (color-rgb-to-hsv): New function.
(list-colors-sort): New defcustom.
(list-colors-sort-key): New function.
(list-colors-display): Doc fix. Sort list according to the option
`list-colors-sort'.
(list-colors-print): Add HSV values to `help-echo' property of
RGB strings.
| -rw-r--r-- | etc/NEWS | 3 | ||||
| -rw-r--r-- | lisp/ChangeLog | 11 | ||||
| -rw-r--r-- | lisp/facemenu.el | 110 |
3 files changed, 120 insertions, 4 deletions
| @@ -125,6 +125,9 @@ trashing. This avoids inadvertently trashing temporary files. | |||
| 125 | *** Calling `delete-file' or `delete-directory' with a prefix argument | 125 | *** Calling `delete-file' or `delete-directory' with a prefix argument |
| 126 | now forces true deletion, regardless of `delete-by-moving-to-trash'. | 126 | now forces true deletion, regardless of `delete-by-moving-to-trash'. |
| 127 | 127 | ||
| 128 | ** New option `list-colors-sort' defines the color sort order | ||
| 129 | for `list-colors-display'. | ||
| 130 | |||
| 128 | 131 | ||
| 129 | * Editing Changes in Emacs 24.1 | 132 | * Editing Changes in Emacs 24.1 |
| 130 | 133 | ||
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 1afc00e9214..e7303f63f00 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,5 +1,16 @@ | |||
| 1 | 2010-06-14 Juri Linkov <juri@jurta.org> | 1 | 2010-06-14 Juri Linkov <juri@jurta.org> |
| 2 | 2 | ||
| 3 | Add sort option `list-colors-sort'. (Bug#6332) | ||
| 4 | * facemenu.el (color-rgb-to-hsv): New function. | ||
| 5 | (list-colors-sort): New defcustom. | ||
| 6 | (list-colors-sort-key): New function. | ||
| 7 | (list-colors-display): Doc fix. Sort list according to the option | ||
| 8 | `list-colors-sort'. | ||
| 9 | (list-colors-print): Add HSV values to `help-echo' property of | ||
| 10 | RGB strings. | ||
| 11 | |||
| 12 | 2010-06-14 Juri Linkov <juri@jurta.org> | ||
| 13 | |||
| 3 | * compare-w.el: Move to the "vc" subdirectory. | 14 | * compare-w.el: Move to the "vc" subdirectory. |
| 4 | 15 | ||
| 5 | 2010-06-14 Stefan Monnier <monnier@iro.umontreal.ca> | 16 | 2010-06-14 Stefan Monnier <monnier@iro.umontreal.ca> |
diff --git a/lisp/facemenu.el b/lisp/facemenu.el index 187383d44e2..9e8299720a6 100644 --- a/lisp/facemenu.el +++ b/lisp/facemenu.el | |||
| @@ -479,6 +479,73 @@ These special properties include `invisible', `intangible' and `read-only'." | |||
| 479 | nil | 479 | nil |
| 480 | col))) | 480 | col))) |
| 481 | 481 | ||
| 482 | (defun color-rgb-to-hsv (r g b) | ||
| 483 | "For R, G, B color components return a list of hue, saturation, value. | ||
| 484 | R, G, B input values should be in [0..65535] range. | ||
| 485 | Output values for hue are integers in [0..360] range. | ||
| 486 | Output values for saturation and value are integers in [0..100] range." | ||
| 487 | (let* ((r (/ r 65535.0)) | ||
| 488 | (g (/ g 65535.0)) | ||
| 489 | (b (/ b 65535.0)) | ||
| 490 | (max (max r g b)) | ||
| 491 | (min (min r g b)) | ||
| 492 | (h (cond ((= max min) 0) | ||
| 493 | ((= max r) (mod (+ (* 60 (/ (- g b) (- max min))) 360) 360)) | ||
| 494 | ((= max g) (+ (* 60 (/ (- b r) (- max min))) 120)) | ||
| 495 | ((= max b) (+ (* 60 (/ (- r g) (- max min))) 240)))) | ||
| 496 | (s (cond ((= max 0) 0) | ||
| 497 | (t (- 1 (/ min max))))) | ||
| 498 | (v max)) | ||
| 499 | (list (round h) (round s 0.01) (round v 0.01)))) | ||
| 500 | |||
| 501 | (defcustom list-colors-sort nil | ||
| 502 | "Color sort order for `list-colors-display'. | ||
| 503 | `nil' means default implementation-dependent order (defined in `x-colors'). | ||
| 504 | `name' sorts by color name. | ||
| 505 | `rgb' sorts by red, green, blue components. | ||
| 506 | `rgb-dist' sorts by the RGB distance to the specified color. | ||
| 507 | `hsv' sorts by hue, saturation, value. | ||
| 508 | `hsv-dist' sorts by the HVS distance to the specified color | ||
| 509 | and excludes grayscale colors." | ||
| 510 | :type '(choice (const :tag "Unsorted" nil) | ||
| 511 | (const :tag "Color Name" name) | ||
| 512 | (const :tag "Red-Green-Blue" rgb) | ||
| 513 | (cons :tag "Distance on RGB cube" | ||
| 514 | (const :tag "Distance from Color" rgb-dist) | ||
| 515 | (color :tag "Source Color Name")) | ||
| 516 | (const :tag "Hue-Saturation-Value" hsv) | ||
| 517 | (cons :tag "Distance on HSV cylinder" | ||
| 518 | (const :tag "Distance from Color" hsv-dist) | ||
| 519 | (color :tag "Source Color Name"))) | ||
| 520 | :group 'facemenu | ||
| 521 | :version "24.1") | ||
| 522 | |||
| 523 | (defun list-colors-sort-key (color) | ||
| 524 | "Return a list of keys for sorting colors depending on `list-colors-sort'. | ||
| 525 | COLOR is the name of the color. When return value is nil, | ||
| 526 | filter out the color from the output." | ||
| 527 | (cond | ||
| 528 | ((null list-colors-sort) color) | ||
| 529 | ((eq list-colors-sort 'name) | ||
| 530 | (downcase color)) | ||
| 531 | ((eq list-colors-sort 'rgb) | ||
| 532 | (color-values color)) | ||
| 533 | ((eq (car-safe list-colors-sort) 'rgb-dist) | ||
| 534 | (color-distance color (cdr list-colors-sort))) | ||
| 535 | ((eq list-colors-sort 'hsv) | ||
| 536 | (apply 'color-rgb-to-hsv (color-values color))) | ||
| 537 | ((eq (car-safe list-colors-sort) 'hsv-dist) | ||
| 538 | (let* ((c-rgb (color-values color)) | ||
| 539 | (c-hsv (apply 'color-rgb-to-hsv c-rgb)) | ||
| 540 | (o-hsv (apply 'color-rgb-to-hsv | ||
| 541 | (color-values (cdr list-colors-sort))))) | ||
| 542 | (unless (and (eq (nth 0 c-rgb) (nth 1 c-rgb)) ; exclude grayscale | ||
| 543 | (eq (nth 1 c-rgb) (nth 2 c-rgb))) | ||
| 544 | ;; 3D Euclidean distance (sqrt is not needed for sorting) | ||
| 545 | (+ (expt (- 180 (abs (- 180 (abs (- (nth 0 c-hsv) ; wrap hue | ||
| 546 | (nth 0 o-hsv)))))) 2) | ||
| 547 | (expt (- (nth 1 c-hsv) (nth 1 o-hsv)) 2) | ||
| 548 | (expt (- (nth 2 c-hsv) (nth 2 o-hsv)) 2))))))) | ||
| 482 | 549 | ||
| 483 | (defun list-colors-display (&optional list buffer-name callback) | 550 | (defun list-colors-display (&optional list buffer-name callback) |
| 484 | "Display names of defined colors, and show what they look like. | 551 | "Display names of defined colors, and show what they look like. |
| @@ -492,10 +559,38 @@ If the optional argument BUFFER-NAME is nil, it defaults to | |||
| 492 | If the optional argument CALLBACK is non-nil, it should be a | 559 | If the optional argument CALLBACK is non-nil, it should be a |
| 493 | function to call each time the user types RET or clicks on a | 560 | function to call each time the user types RET or clicks on a |
| 494 | color. The function should accept a single argument, the color | 561 | color. The function should accept a single argument, the color |
| 495 | name." | 562 | name. |
| 563 | |||
| 564 | You can change the color sort order by customizing `list-colors-sort'." | ||
| 496 | (interactive) | 565 | (interactive) |
| 497 | (when (and (null list) (> (display-color-cells) 0)) | 566 | (when (and (null list) (> (display-color-cells) 0)) |
| 498 | (setq list (list-colors-duplicates (defined-colors))) | 567 | (setq list (list-colors-duplicates (defined-colors))) |
| 568 | (when list-colors-sort | ||
| 569 | ;; Schwartzian transform with `(color key1 key2 key3 ...)'. | ||
| 570 | (setq list (mapcar | ||
| 571 | 'car | ||
| 572 | (sort (delq nil (mapcar | ||
| 573 | (lambda (c) | ||
| 574 | (let ((key (list-colors-sort-key | ||
| 575 | (car c)))) | ||
| 576 | (when key | ||
| 577 | (cons c (if (consp key) key | ||
| 578 | (list key)))))) | ||
| 579 | list)) | ||
| 580 | (lambda (a b) | ||
| 581 | (let* ((a-keys (cdr a)) | ||
| 582 | (b-keys (cdr b)) | ||
| 583 | (a-key (car a-keys)) | ||
| 584 | (b-key (car b-keys))) | ||
| 585 | ;; Skip common keys at the beginning of key lists. | ||
| 586 | (while (and a-key b-key (equal a-key b-key)) | ||
| 587 | (setq a-keys (cdr a-keys) a-key (car a-keys) | ||
| 588 | b-keys (cdr b-keys) b-key (car b-keys))) | ||
| 589 | (cond | ||
| 590 | ((and (numberp a-key) (numberp b-key)) | ||
| 591 | (< a-key b-key)) | ||
| 592 | ((and (stringp a-key) (stringp b-key)) | ||
| 593 | (string< a-key b-key))))))))) | ||
| 499 | (when (memq (display-visual-class) '(gray-scale pseudo-color direct-color)) | 594 | (when (memq (display-visual-class) '(gray-scale pseudo-color direct-color)) |
| 500 | ;; Don't show more than what the display can handle. | 595 | ;; Don't show more than what the display can handle. |
| 501 | (let ((lc (nthcdr (1- (display-color-cells)) list))) | 596 | (let ((lc (nthcdr (1- (display-color-cells)) list))) |
| @@ -550,9 +645,16 @@ name." | |||
| 550 | (point) | 645 | (point) |
| 551 | 'face (list :foreground (car color))) | 646 | 'face (list :foreground (car color))) |
| 552 | (indent-to (max (- (window-width) 8) 44)) | 647 | (indent-to (max (- (window-width) 8) 44)) |
| 553 | (insert (apply 'format "#%02x%02x%02x" | 648 | (insert (propertize |
| 554 | (mapcar (lambda (c) (lsh c -8)) | 649 | (apply 'format "#%02x%02x%02x" |
| 555 | color-values))) | 650 | (mapcar (lambda (c) (lsh c -8)) |
| 651 | color-values)) | ||
| 652 | 'mouse-face 'highlight | ||
| 653 | 'help-echo | ||
| 654 | (let ((hsv (apply 'color-rgb-to-hsv | ||
| 655 | (color-values (car color))))) | ||
| 656 | (format "H:%d S:%d V:%d" | ||
| 657 | (nth 0 hsv) (nth 1 hsv) (nth 2 hsv))))) | ||
| 556 | (when callback | 658 | (when callback |
| 557 | (make-text-button | 659 | (make-text-button |
| 558 | opoint (point) | 660 | opoint (point) |