Use "#+attr_org: :radio" before lists to enable radio buttons
* doc/org-manual.org (Checkboxes): Document the use of "#+attr_org". * lisp/org.el (org-ctrl-c-ctrl-c): When the list at point is preceded by "#+attr_org: :radio" use `org-toggle-radio-button' instead of `org-toggle-checkbox'. * lisp/org-list.el (org-at-radio-list-p): New defsubst. (org-toggle-checkbox): Use it. * etc/ORG-NEWS: Document the use of "#+attr_org".
This commit is contained in:
parent
561feb128d
commit
4028cc731b
|
@ -4539,12 +4539,13 @@ The following commands work with checkboxes:
|
|||
Toggle checkbox status by using the checkbox of the item at point as
|
||||
a radio button: when turned on, all other checkboxes on the same
|
||||
level will be turned off. With a universal prefix argument, toggle
|
||||
the presence of the checkbox. With double prefix argument, set it
|
||||
the presence of the checkbox. With a double prefix argument, set it
|
||||
to =[-]=.
|
||||
|
||||
#+findex: org-list-checkbox-radio-mode
|
||||
{{{kdb(C-c C-c)}}} can be told to consider checkboxes as radio buttons
|
||||
by calling {{{kbd(M-x org-list-checkbox-radio-mode)}}}, as minor mode.
|
||||
{{{kdb(C-c C-c)}}} can be told to consider checkboxes as radio buttons by
|
||||
setting =#+ATTR_ORG: :radio= right before the list or by calling
|
||||
{{{kbd(M-x org-list-checkbox-radio-mode)}}} to activate this minor mode.
|
||||
|
||||
- {{{kbd(M-S-RET)}}} (~org-insert-todo-heading~) ::
|
||||
|
||||
|
|
|
@ -54,6 +54,9 @@ If you want to occasionally toggle a checkbox as a radio button
|
|||
without turning this minor mode on, you can use =<C-c C-x C-r>= to
|
||||
call ~org-toggle-radio-button~.
|
||||
|
||||
You can also add =#+ATTR_ORG: :radio= right before the list to tell
|
||||
Org to use radio buttons for this list only.
|
||||
|
||||
*** Looping agenda commands over headlines
|
||||
|
||||
~org-agenda-loop-over-headlines-in-active-region~ allows you to loop
|
||||
|
|
182
lisp/org-list.el
182
lisp/org-list.el
|
@ -2337,6 +2337,16 @@ is an integer, 0 means `-', 1 means `+' etc. If WHICH is
|
|||
(org-list-struct-apply-struct struct old-struct)
|
||||
(org-update-checkbox-count-maybe))))
|
||||
|
||||
(defsubst org-at-radio-list-p ()
|
||||
"Is point in a list with radio buttons?"
|
||||
(let (attr)
|
||||
(save-excursion
|
||||
(org-at-item-p)
|
||||
(goto-char (caar (org-list-struct)))
|
||||
(org-backward-element)
|
||||
(setq attr (car (org-element-property :attr_org (org-element-at-point))))
|
||||
(when attr (string-match-p ":radio" attr)))))
|
||||
|
||||
(defun org-toggle-checkbox (&optional toggle-presence)
|
||||
"Toggle the checkbox in the current line.
|
||||
|
||||
|
@ -2351,92 +2361,94 @@ If point is on a headline, apply this to all checkbox items in
|
|||
the text below the heading, taking as reference the first item in
|
||||
subtree, ignoring planning line and any drawer following it."
|
||||
(interactive "P")
|
||||
(save-excursion
|
||||
(let* (singlep
|
||||
block-item
|
||||
lim-up
|
||||
lim-down
|
||||
(orderedp (org-entry-get nil "ORDERED"))
|
||||
(_bounds
|
||||
;; In a region, start at first item in region.
|
||||
(if (org-at-radio-list-p)
|
||||
(org-toggle-radio-button toggle-presence)
|
||||
(save-excursion
|
||||
(let* (singlep
|
||||
block-item
|
||||
lim-up
|
||||
lim-down
|
||||
(orderedp (org-entry-get nil "ORDERED"))
|
||||
(_bounds
|
||||
;; In a region, start at first item in region.
|
||||
(cond
|
||||
((org-region-active-p)
|
||||
(let ((limit (region-end)))
|
||||
(goto-char (region-beginning))
|
||||
(if (org-list-search-forward (org-item-beginning-re) limit t)
|
||||
(setq lim-up (point-at-bol))
|
||||
(error "No item in region"))
|
||||
(setq lim-down (copy-marker limit))))
|
||||
((org-at-heading-p)
|
||||
;; On a heading, start at first item after drawers and
|
||||
;; time-stamps (scheduled, etc.).
|
||||
(let ((limit (save-excursion (outline-next-heading) (point))))
|
||||
(org-end-of-meta-data t)
|
||||
(if (org-list-search-forward (org-item-beginning-re) limit t)
|
||||
(setq lim-up (point-at-bol))
|
||||
(error "No item in subtree"))
|
||||
(setq lim-down (copy-marker limit))))
|
||||
;; Just one item: set SINGLEP flag.
|
||||
((org-at-item-p)
|
||||
(setq singlep t)
|
||||
(setq lim-up (point-at-bol)
|
||||
lim-down (copy-marker (point-at-eol))))
|
||||
(t (error "Not at an item or heading, and no active region"))))
|
||||
;; Determine the checkbox going to be applied to all items
|
||||
;; within bounds.
|
||||
(ref-checkbox
|
||||
(progn
|
||||
(goto-char lim-up)
|
||||
(let ((cbox (and (org-at-item-checkbox-p) (match-string 1))))
|
||||
(cond
|
||||
((equal toggle-presence '(16)) "[-]")
|
||||
((equal toggle-presence '(4))
|
||||
(unless cbox "[ ]"))
|
||||
((equal "[X]" cbox) "[ ]")
|
||||
(t "[X]"))))))
|
||||
;; When an item is found within bounds, grab the full list at
|
||||
;; point structure, then: (1) set check-box of all its items
|
||||
;; within bounds to REF-CHECKBOX, (2) fix check-boxes of the
|
||||
;; whole list, (3) move point after the list.
|
||||
(goto-char lim-up)
|
||||
(while (and (< (point) lim-down)
|
||||
(org-list-search-forward (org-item-beginning-re)
|
||||
lim-down 'move))
|
||||
(let* ((struct (org-list-struct))
|
||||
(struct-copy (copy-tree struct))
|
||||
(parents (org-list-parents-alist struct))
|
||||
(prevs (org-list-prevs-alist struct))
|
||||
(bottom (copy-marker (org-list-get-bottom-point struct)))
|
||||
(items-to-toggle (cl-remove-if
|
||||
(lambda (e) (or (< e lim-up) (> e lim-down)))
|
||||
(mapcar #'car struct))))
|
||||
(mapc (lambda (e) (org-list-set-checkbox
|
||||
e struct
|
||||
;; If there is no box at item, leave as-is
|
||||
;; unless function was called with C-u prefix.
|
||||
(let ((cur-box (org-list-get-checkbox e struct)))
|
||||
(if (or cur-box (equal toggle-presence '(4)))
|
||||
ref-checkbox
|
||||
cur-box))))
|
||||
items-to-toggle)
|
||||
(setq block-item (org-list-struct-fix-box
|
||||
struct parents prevs orderedp))
|
||||
;; Report some problems due to ORDERED status of subtree.
|
||||
;; If only one box was being checked, throw an error, else,
|
||||
;; only signal problems.
|
||||
(cond
|
||||
((org-region-active-p)
|
||||
(let ((limit (region-end)))
|
||||
(goto-char (region-beginning))
|
||||
(if (org-list-search-forward (org-item-beginning-re) limit t)
|
||||
(setq lim-up (point-at-bol))
|
||||
(error "No item in region"))
|
||||
(setq lim-down (copy-marker limit))))
|
||||
((org-at-heading-p)
|
||||
;; On a heading, start at first item after drawers and
|
||||
;; time-stamps (scheduled, etc.).
|
||||
(let ((limit (save-excursion (outline-next-heading) (point))))
|
||||
(org-end-of-meta-data t)
|
||||
(if (org-list-search-forward (org-item-beginning-re) limit t)
|
||||
(setq lim-up (point-at-bol))
|
||||
(error "No item in subtree"))
|
||||
(setq lim-down (copy-marker limit))))
|
||||
;; Just one item: set SINGLEP flag.
|
||||
((org-at-item-p)
|
||||
(setq singlep t)
|
||||
(setq lim-up (point-at-bol)
|
||||
lim-down (copy-marker (point-at-eol))))
|
||||
(t (error "Not at an item or heading, and no active region"))))
|
||||
;; Determine the checkbox going to be applied to all items
|
||||
;; within bounds.
|
||||
(ref-checkbox
|
||||
(progn
|
||||
(goto-char lim-up)
|
||||
(let ((cbox (and (org-at-item-checkbox-p) (match-string 1))))
|
||||
(cond
|
||||
((equal toggle-presence '(16)) "[-]")
|
||||
((equal toggle-presence '(4))
|
||||
(unless cbox "[ ]"))
|
||||
((equal "[X]" cbox) "[ ]")
|
||||
(t "[X]"))))))
|
||||
;; When an item is found within bounds, grab the full list at
|
||||
;; point structure, then: (1) set check-box of all its items
|
||||
;; within bounds to REF-CHECKBOX, (2) fix check-boxes of the
|
||||
;; whole list, (3) move point after the list.
|
||||
(goto-char lim-up)
|
||||
(while (and (< (point) lim-down)
|
||||
(org-list-search-forward (org-item-beginning-re)
|
||||
lim-down 'move))
|
||||
(let* ((struct (org-list-struct))
|
||||
(struct-copy (copy-tree struct))
|
||||
(parents (org-list-parents-alist struct))
|
||||
(prevs (org-list-prevs-alist struct))
|
||||
(bottom (copy-marker (org-list-get-bottom-point struct)))
|
||||
(items-to-toggle (cl-remove-if
|
||||
(lambda (e) (or (< e lim-up) (> e lim-down)))
|
||||
(mapcar #'car struct))))
|
||||
(mapc (lambda (e) (org-list-set-checkbox
|
||||
e struct
|
||||
;; If there is no box at item, leave as-is
|
||||
;; unless function was called with C-u prefix.
|
||||
(let ((cur-box (org-list-get-checkbox e struct)))
|
||||
(if (or cur-box (equal toggle-presence '(4)))
|
||||
ref-checkbox
|
||||
cur-box))))
|
||||
items-to-toggle)
|
||||
(setq block-item (org-list-struct-fix-box
|
||||
struct parents prevs orderedp))
|
||||
;; Report some problems due to ORDERED status of subtree.
|
||||
;; If only one box was being checked, throw an error, else,
|
||||
;; only signal problems.
|
||||
(cond
|
||||
((and singlep block-item (> lim-up block-item))
|
||||
(error
|
||||
"Checkbox blocked because of unchecked box at line %d"
|
||||
(org-current-line block-item)))
|
||||
(block-item
|
||||
(message
|
||||
"Checkboxes were removed due to unchecked box at line %d"
|
||||
(org-current-line block-item))))
|
||||
(goto-char bottom)
|
||||
(move-marker bottom nil)
|
||||
(org-list-struct-apply-struct struct struct-copy)))
|
||||
(move-marker lim-down nil)))
|
||||
((and singlep block-item (> lim-up block-item))
|
||||
(error
|
||||
"Checkbox blocked because of unchecked box at line %d"
|
||||
(org-current-line block-item)))
|
||||
(block-item
|
||||
(message
|
||||
"Checkboxes were removed due to unchecked box at line %d"
|
||||
(org-current-line block-item))))
|
||||
(goto-char bottom)
|
||||
(move-marker bottom nil)
|
||||
(org-list-struct-apply-struct struct struct-copy)))
|
||||
(move-marker lim-down nil))))
|
||||
(org-update-checkbox-count-maybe))
|
||||
|
||||
(defun org-reset-checkbox-state-subtree ()
|
||||
|
|
11
lisp/org.el
11
lisp/org.el
|
@ -17171,6 +17171,7 @@ This command does many different things, depending on context:
|
|||
src-block statistics-cookie table table-cell table-row
|
||||
timestamp)
|
||||
t))
|
||||
(radio-list-p (org-at-radio-list-p))
|
||||
(type (org-element-type context)))
|
||||
;; For convenience: at the first line of a paragraph on the same
|
||||
;; line as an item, apply function on that item instead.
|
||||
|
@ -17217,8 +17218,9 @@ This command does many different things, depending on context:
|
|||
;; unconditionally, whereas `C-u' will toggle its presence.
|
||||
;; Without a universal argument, if the item has a checkbox,
|
||||
;; toggle it. Otherwise repair the list.
|
||||
(if (and (boundp org-list-checkbox-radio-mode)
|
||||
org-list-checkbox-radio-mode)
|
||||
(if (or radio-list-p
|
||||
(and (boundp org-list-checkbox-radio-mode)
|
||||
org-list-checkbox-radio-mode))
|
||||
(org-toggle-radio-button arg)
|
||||
(let* ((box (org-element-property :checkbox context))
|
||||
(struct (org-element-property :structure context))
|
||||
|
@ -17259,8 +17261,9 @@ This command does many different things, depending on context:
|
|||
;; will toggle their presence according to the state of the
|
||||
;; first item in the list. Without an argument, repair the
|
||||
;; list.
|
||||
(if (and (boundp org-list-checkbox-radio-mode)
|
||||
org-list-checkbox-radio-mode)
|
||||
(if (or radio-list-p
|
||||
(and (boundp org-list-checkbox-radio-mode)
|
||||
org-list-checkbox-radio-mode))
|
||||
(org-toggle-radio-button arg)
|
||||
(let* ((begin (org-element-property :contents-begin context))
|
||||
(struct (org-element-property :structure context))
|
||||
|
|
Loading…
Reference in New Issue