mirror of
https://git.savannah.gnu.org/git/emacs/org-mode.git
synced 2024-10-18 02:19:46 +00:00
Add `org-toggle-radio-button' and related minor mode
* doc/org-manual.org (Checkboxes): Document the new minor mode and command. * lisp/org-keys.el (org-mode-map): Bind C-c C-x C-r to `org-toggle-radio-button'. * lisp/org-list.el (org-list-checkbox-radio-mode): New minor mode to let C-c C-c call `org-toggle-radio-button' instead of `org-toggle-checkbox'. (org-toggle-radio-button): New command. * lisp/org.el (org-ctrl-c-ctrl-c): Use `org-toggle-radio-button'. * etc/ORG-NEWS: Document the new minor mode and command. Thanks to Phil Sainty for sharing this idea and links to similar implementations.
This commit is contained in:
parent
8f59e01aa8
commit
561feb128d
@ -4531,6 +4531,21 @@ The following commands work with checkboxes:
|
||||
|
||||
- If there is no active region, just toggle the checkbox at point.
|
||||
|
||||
- {{{kbd(C-c C-x C-r)}}} (~org-toggle-radio-button~) ::
|
||||
|
||||
#+kindex: C-c C-x C-r
|
||||
#+findex: org-toggle-radio-button
|
||||
#+cindex: radio button, checkbox as
|
||||
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
|
||||
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.
|
||||
|
||||
- {{{kbd(M-S-RET)}}} (~org-insert-todo-heading~) ::
|
||||
|
||||
#+kindex: M-S-RET
|
||||
|
10
etc/ORG-NEWS
10
etc/ORG-NEWS
@ -44,6 +44,16 @@ You can activate this minor mode by default by setting the option
|
||||
~org-table-header-line-p~ to =t=. You can also change the face for
|
||||
the header line by customizing the ~org-table-header~ face.
|
||||
|
||||
*** New minor mode ~org-list-checkbox-radio-mode~
|
||||
|
||||
When this minor mode is on, checkboxes behave as radio buttons: if a
|
||||
checkbox is turned on, other checkboxes at the same level are turned
|
||||
off.
|
||||
|
||||
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~.
|
||||
|
||||
*** Looping agenda commands over headlines
|
||||
|
||||
~org-agenda-loop-over-headlines-in-active-region~ allows you to loop
|
||||
|
@ -196,6 +196,7 @@
|
||||
(declare-function org-todo "org" (&optional arg1))
|
||||
(declare-function org-toggle-archive-tag "org" (&optional find-done))
|
||||
(declare-function org-toggle-checkbox "org" (&optional toggle-presence))
|
||||
(declare-function org-toggle-radio-button "org" (&optional arg))
|
||||
(declare-function org-toggle-comment "org" ())
|
||||
(declare-function org-toggle-fixed-width "org" ())
|
||||
(declare-function org-toggle-inline-images "org" (&optional include-linked))
|
||||
@ -658,6 +659,7 @@ COMMANDS is a list of alternating OLDDEF NEWDEF command names."
|
||||
(org-defkey org-mode-map (kbd "C-c C-x C-M-v") #'org-redisplay-inline-images)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x \\") #'org-toggle-pretty-entities)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x C-b") #'org-toggle-checkbox)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x C-r") #'org-toggle-radio-button)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x p") #'org-set-property)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x P") #'org-set-property-and-value)
|
||||
(org-defkey org-mode-map (kbd "C-c C-x e") #'org-set-effort)
|
||||
|
@ -2302,6 +2302,41 @@ is an integer, 0 means `-', 1 means `+' etc. If WHICH is
|
||||
(org-list-struct-fix-ind struct parents)
|
||||
(org-list-struct-apply-struct struct old-struct)))))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode org-list-checkbox-radio-mode
|
||||
"When turned on, use list checkboxes as radio buttons."
|
||||
nil " CheckBoxRadio" nil
|
||||
(unless (eq major-mode 'org-mode)
|
||||
(user-error "Cannot turn this mode outside org-mode buffers")))
|
||||
|
||||
(defun org-toggle-radio-button (&optional arg)
|
||||
"Toggle off all checkboxes and toggle on the one at point."
|
||||
(interactive "P")
|
||||
(if (not (org-at-item-p))
|
||||
(user-error "Cannot toggle checkbox outside of a list")
|
||||
(let* ((cpos (org-in-item-p))
|
||||
(struct (org-list-struct))
|
||||
(orderedp (org-entry-get nil "ORDERED"))
|
||||
(parents (org-list-parents-alist struct))
|
||||
(old-struct (copy-tree struct))
|
||||
(cbox (org-list-get-checkbox cpos struct))
|
||||
(prevs (org-list-prevs-alist struct))
|
||||
(start (org-list-get-list-begin (point-at-bol) struct prevs))
|
||||
(new (unless (and cbox (equal arg '(4)) (equal start cpos))
|
||||
"[ ]")))
|
||||
(dolist (pos (org-list-get-all-items
|
||||
start struct (org-list-prevs-alist struct)))
|
||||
(org-list-set-checkbox pos struct new))
|
||||
(when new
|
||||
(org-list-set-checkbox
|
||||
cpos struct
|
||||
(cond ((equal arg '(4)) (unless cbox "[ ]"))
|
||||
((equal arg '(16)) (unless cbox "[-]"))
|
||||
(t (if (equal cbox "[X]") "[ ]" "[X]")))))
|
||||
(org-list-struct-fix-box struct parents prevs orderedp)
|
||||
(org-list-struct-apply-struct struct old-struct)
|
||||
(org-update-checkbox-count-maybe))))
|
||||
|
||||
(defun org-toggle-checkbox (&optional toggle-presence)
|
||||
"Toggle the checkbox in the current line.
|
||||
|
||||
|
140
lisp/org.el
140
lisp/org.el
@ -17217,39 +17217,79 @@ 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.
|
||||
(let* ((box (org-element-property :checkbox context))
|
||||
(struct (org-element-property :structure context))
|
||||
(old-struct (copy-tree struct))
|
||||
(parents (org-list-parents-alist struct))
|
||||
(prevs (org-list-prevs-alist struct))
|
||||
(orderedp (org-not-nil (org-entry-get nil "ORDERED"))))
|
||||
(org-list-set-checkbox
|
||||
(org-element-property :begin context) struct
|
||||
(cond ((equal arg '(16)) "[-]")
|
||||
((and (not box) (equal arg '(4))) "[ ]")
|
||||
((or (not box) (equal arg '(4))) nil)
|
||||
((eq box 'on) "[ ]")
|
||||
(t "[X]")))
|
||||
;; Mimic `org-list-write-struct' but with grabbing a return
|
||||
;; value from `org-list-struct-fix-box'.
|
||||
(org-list-struct-fix-ind struct parents 2)
|
||||
(org-list-struct-fix-item-end struct)
|
||||
(org-list-struct-fix-bul struct prevs)
|
||||
(org-list-struct-fix-ind struct parents)
|
||||
(let ((block-item
|
||||
(org-list-struct-fix-box struct parents prevs orderedp)))
|
||||
(if (and box (equal struct old-struct))
|
||||
(if (equal arg '(16))
|
||||
(message "Checkboxes already reset")
|
||||
(user-error "Cannot toggle this checkbox: %s"
|
||||
(if (eq box 'on)
|
||||
"all subitems checked"
|
||||
"unchecked subitems")))
|
||||
(org-list-struct-apply-struct struct old-struct)
|
||||
(org-update-checkbox-count-maybe))
|
||||
(when block-item
|
||||
(message "Checkboxes were removed due to empty box at line %d"
|
||||
(org-current-line block-item))))))
|
||||
(if (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))
|
||||
(old-struct (copy-tree struct))
|
||||
(parents (org-list-parents-alist struct))
|
||||
(prevs (org-list-prevs-alist struct))
|
||||
(orderedp (org-not-nil (org-entry-get nil "ORDERED"))))
|
||||
(org-list-set-checkbox
|
||||
(org-element-property :begin context) struct
|
||||
(cond ((equal arg '(16)) "[-]")
|
||||
((and (not box) (equal arg '(4))) "[ ]")
|
||||
((or (not box) (equal arg '(4))) nil)
|
||||
((eq box 'on) "[ ]")
|
||||
(t "[X]")))
|
||||
;; Mimic `org-list-write-struct' but with grabbing a return
|
||||
;; value from `org-list-struct-fix-box'.
|
||||
(org-list-struct-fix-ind struct parents 2)
|
||||
(org-list-struct-fix-item-end struct)
|
||||
(org-list-struct-fix-bul struct prevs)
|
||||
(org-list-struct-fix-ind struct parents)
|
||||
(let ((block-item
|
||||
(org-list-struct-fix-box struct parents prevs orderedp)))
|
||||
(if (and box (equal struct old-struct))
|
||||
(if (equal arg '(16))
|
||||
(message "Checkboxes already reset")
|
||||
(user-error "Cannot toggle this checkbox: %s"
|
||||
(if (eq box 'on)
|
||||
"all subitems checked"
|
||||
"unchecked subitems")))
|
||||
(org-list-struct-apply-struct struct old-struct)
|
||||
(org-update-checkbox-count-maybe))
|
||||
(when block-item
|
||||
(message "Checkboxes were removed due to empty box at line %d"
|
||||
(org-current-line block-item)))))))
|
||||
(`plain-list
|
||||
;; At a plain list, with a double C-u argument, set
|
||||
;; checkboxes of each item to "[-]", whereas a single one
|
||||
;; 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)
|
||||
(org-toggle-radio-button arg)
|
||||
(let* ((begin (org-element-property :contents-begin context))
|
||||
(struct (org-element-property :structure context))
|
||||
(old-struct (copy-tree struct))
|
||||
(first-box (save-excursion
|
||||
(goto-char begin)
|
||||
(looking-at org-list-full-item-re)
|
||||
(match-string-no-properties 3)))
|
||||
(new-box (cond ((equal arg '(16)) "[-]")
|
||||
((equal arg '(4)) (unless first-box "[ ]"))
|
||||
((equal first-box "[X]") "[ ]")
|
||||
(t "[X]"))))
|
||||
(cond
|
||||
(arg
|
||||
(dolist (pos
|
||||
(org-list-get-all-items
|
||||
begin struct (org-list-prevs-alist struct)))
|
||||
(org-list-set-checkbox pos struct new-box)))
|
||||
((and first-box (eq (point) begin))
|
||||
;; For convenience, when point is at bol on the first
|
||||
;; item of the list and no argument is provided, simply
|
||||
;; toggle checkbox of that item, if any.
|
||||
(org-list-set-checkbox begin struct new-box)))
|
||||
(when (equal
|
||||
(org-list-write-struct
|
||||
struct (org-list-parents-alist struct) old-struct)
|
||||
old-struct)
|
||||
(message "Cannot update this checkbox"))
|
||||
(org-update-checkbox-count-maybe))))
|
||||
(`keyword
|
||||
(let ((org-inhibit-startup-visibility-stuff t)
|
||||
(org-startup-align-all-tables nil))
|
||||
@ -17258,40 +17298,6 @@ This command does many different things, depending on context:
|
||||
(setq org-table-coordinate-overlays nil))
|
||||
(org-save-outline-visibility 'use-markers (org-mode-restart)))
|
||||
(message "Local setup has been refreshed"))
|
||||
(`plain-list
|
||||
;; At a plain list, with a double C-u argument, set
|
||||
;; checkboxes of each item to "[-]", whereas a single one
|
||||
;; will toggle their presence according to the state of the
|
||||
;; first item in the list. Without an argument, repair the
|
||||
;; list.
|
||||
(let* ((begin (org-element-property :contents-begin context))
|
||||
(struct (org-element-property :structure context))
|
||||
(old-struct (copy-tree struct))
|
||||
(first-box (save-excursion
|
||||
(goto-char begin)
|
||||
(looking-at org-list-full-item-re)
|
||||
(match-string-no-properties 3)))
|
||||
(new-box (cond ((equal arg '(16)) "[-]")
|
||||
((equal arg '(4)) (unless first-box "[ ]"))
|
||||
((equal first-box "[X]") "[ ]")
|
||||
(t "[X]"))))
|
||||
(cond
|
||||
(arg
|
||||
(dolist (pos
|
||||
(org-list-get-all-items
|
||||
begin struct (org-list-prevs-alist struct)))
|
||||
(org-list-set-checkbox pos struct new-box)))
|
||||
((and first-box (eq (point) begin))
|
||||
;; For convenience, when point is at bol on the first
|
||||
;; item of the list and no argument is provided, simply
|
||||
;; toggle checkbox of that item, if any.
|
||||
(org-list-set-checkbox begin struct new-box)))
|
||||
(when (equal
|
||||
(org-list-write-struct
|
||||
struct (org-list-parents-alist struct) old-struct)
|
||||
old-struct)
|
||||
(message "Cannot update this checkbox"))
|
||||
(org-update-checkbox-count-maybe)))
|
||||
((or `property-drawer `node-property)
|
||||
(call-interactively #'org-property-action))
|
||||
(`radio-target
|
||||
|
Loading…
Reference in New Issue
Block a user