Hi,
On 3/24/11 12:47 PM, Le Wang wrote:
(...)
> Is it possible to inline count-down timers in a cooking step? For
> example "2. simmer sauce for 40 minutes on low heat.
> <start_timer_button>", so there is a button at the end of the line
> that starts a count-down timer.
>
> Many timers from different steps can be started simultaneously, and
> each timer should be able to be paused and restarted. And there
> should be an easy way to get an overview of of all ongoing timers from
> the current document.
>
> Is it possible to hack this together using existing org >
functionality?
I don't think Org has built-in support for concurrent countdown
timers. But you can fake this pretty well with org-timer, properties,
column view, a dynamic block, and some lisp table formulas.
A ready-to-run example is attached, hopefully self-explanatory,
probably buggy, and WITH ABSOLUTELY NO WARRANTY. This is a learning
exercise for me.
Instead of using a start timer button (for which you could use an
`elisp:' link, like the one I've put in to make it easy to stop the
timer), you can write a hook to start countdowns when the TODO state
changes. That rather hackish function is the only code here that's not
out of the box.
Yours,
Christian
#+STARTUP: showeverything
#+COLUMNS: %ITEM %For %Start %Elapsed %REMAINS %Message
#+TODO: TODO RUNNING | DONE
Recipe with timers
* First evaluate this (or put in your .emacs)
#+begin_src emacs-lisp
(require 'org-timer)
(defun my/recipe-timer-start ()
"When state is changed to `RUNNING', change the `Start'
property of the entry to the current value of org-timer if this
is a timed recipe entry, i.e. if it has a h:m:s-formatted
duration in its `For' property. When state is changed to `DONE',
reset `Start' to `-'."
(when (string-match org-timer-re (or (org-entry-get (point) "For") ""))
(cond ((string= state "RUNNING")
(org-set-property "Start" (org-timer nil t)))
((string= state "DONE")
(org-set-property "Start" "-")))))
(setq org-after-todo-state-change-hook 'my/recipe-timer-start)
#+end_src
#+results:
: my/recipe-timer-start
* Recipe
Here's the dynamic block with the overview.
- Refresh manually with `C-c C-c' on the `begin' line.
- Note that this will start the timer if it's not running.
- The countdown is in the "REMAINS" column.
#+begin: columnview :id local
| ITEM | For | Start | Elapsed | REMAINS | Message |
|-----------------------+---------+-------+---------+---------+---------|
| * Recipe | | | 0:00:00 | | |
| ** TODO Let simmer | 0:40:00 | - | 0:00:00 | | |
| ** TODO Let ferment | 2:00:00 | - | 0:00:00 | | |
| ** TODO Leave in oven | 0:04:00 | - | 0:00:00 | | |
#+tblfm: $4='(org-timer nil t)::$5='(if (string-match org-timer-re $3)
(org-timer-secs-to-hms (- (org-timer-hms-to-secs $2) (org-timer-hms-to-secs
$4))) "")::$6='(if (< (org-timer-hms-to-secs $5) 0) "STOP!" "")
#+end:
Below are a few tasks with durations in their `For' properties.
- Start them by changing the task's state to `RUNNING' with `C-c C-t'.
(If org-timer is not running, it will be started.)
- When time's up for a task, it will message `STOP!'. Navigate to the
task and change its state to `DONE' with `C-c C-t' (after taking stuff
out of the oven, or whatever).
- When you're done, you can [[elisp:org-timer-stop][stop the timer]] (click the
link or press
`C-u C-c C-x ,').
** TODO Let simmer
:PROPERTIES:
:For: 0:40:00
:Start: -
:END:
** TODO Let ferment
:PROPERTIES:
:For: 2:00:00
:Start: -
:END:
** TODO Leave in oven
:PROPERTIES:
:For: 0:04:00
:Start: -
:END: