guile feature
[bpt/emacs.git] / lisp / calendar / cal-move.el
CommitLineData
0808d911
ER
1;;; cal-move.el --- calendar functions for movement in the calendar
2
ba318903 3;; Copyright (C) 1995, 2001-2014 Free Software Foundation, Inc.
0808d911
ER
4
5;; Author: Edward M. Reingold <reingold@cs.uiuc.edu>
aff88519 6;; Maintainer: Glenn Morris <rgm@gnu.org>
0808d911
ER
7;; Keywords: calendar
8;; Human-Keywords: calendar
bd78fa1d 9;; Package: calendar
0808d911
ER
10
11;; This file is part of GNU Emacs.
12
2ed66575 13;; GNU Emacs is free software: you can redistribute it and/or modify
0808d911 14;; it under the terms of the GNU General Public License as published by
2ed66575
GM
15;; the Free Software Foundation, either version 3 of the License, or
16;; (at your option) any later version.
0808d911
ER
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
2ed66575 24;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
0808d911
ER
25
26;;; Commentary:
27
b36e906d 28;; See calendar.el.
0808d911 29
0808d911
ER
30;;; Code:
31
3eee90de 32;; FIXME should calendar just require this?
cfcc468f
GM
33(require 'calendar)
34
fb6be44a
GM
35
36;; Note that this is not really the "closest" date.
37;; In most cases, it just searches forwards for the next day.
cfcc468f
GM
38;;;###cal-autoload
39(defun calendar-cursor-to-nearest-date ()
40 "Move the cursor to the closest date.
41The position of the cursor is unchanged if it is already on a date.
42Returns the list (month day year) giving the cursor position."
3e0e034b 43 (or (calendar-cursor-to-date)
fb6be44a
GM
44 (let* ((col (current-column))
45 (edges (cdr (assoc (calendar-column-to-segment)
46 calendar-month-edges)))
47 (last (nth 2 edges))
48 (right (nth 3 edges)))
49 (when (< (count-lines (point-min) (point)) calendar-first-date-row)
a8ab722f
GM
50 (goto-char (point-min))
51 (forward-line (1- calendar-first-date-row))
fb6be44a
GM
52 (move-to-column col))
53 ;; The date positions are fixed and computable, but searching
54 ;; is probably more flexible. Need to consider blank days at
55 ;; start and end of month if computing positions.
56 ;; 'date text-property is used to exclude intermonth text.
57 (unless (and (looking-at "[0-9]")
58 (get-text-property (point) 'date))
59 ;; We search forwards for a number, except close to the RH
60 ;; margin of a month, where we search backwards.
61 ;; Note that the searches can go to other lines.
62 (if (or (looking-at " *$")
63 (and (> col last) (< col right)))
64 (while (and (re-search-backward "[0-9]" nil t)
65 (not (get-text-property (point) 'date))))
66 (while (and (re-search-forward "[0-9]" nil t)
67 (not (get-text-property (1- (point)) 'date))))
68 (backward-char 1)))
cfcc468f
GM
69 (calendar-cursor-to-date))))
70
e803eab7 71(defvar displayed-month) ; from calendar-generate
0b0f8fa4
GM
72(defvar displayed-year)
73
cfcc468f
GM
74;;;###cal-autoload
75(defun calendar-cursor-to-visible-date (date)
76 "Move the cursor to DATE that is on the screen."
e803eab7
GM
77 (let ((month (calendar-extract-month date))
78 (day (calendar-extract-day date))
79 (year (calendar-extract-year date)))
a8ab722f
GM
80 (goto-char (point-min))
81 (forward-line (+ calendar-first-date-row -1
82 (/ (+ day -1
83 (mod
84 (- (calendar-day-of-week (list month 1 year))
85 calendar-week-start-day)
86 7))
87 7)))
3eee90de
GM
88 (move-to-column (+ calendar-left-margin (1- calendar-day-digit-width)
89 (* calendar-month-width
cfcc468f
GM
90 (1+ (calendar-interval
91 displayed-month displayed-year month year)))
3eee90de
GM
92 (* calendar-column-width
93 (mod
94 (- (calendar-day-of-week date)
95 calendar-week-start-day)
96 7))))))
20eff799 97
6c1841ba 98;;;###cal-autoload
0808d911
ER
99(defun calendar-goto-today ()
100 "Reposition the calendar window so the current date is visible."
101 (interactive)
cfcc468f 102 (let ((today (calendar-current-date))) ; the date might have changed
0808d911 103 (if (not (calendar-date-is-visible-p today))
e803eab7
GM
104 (calendar-generate-window)
105 (calendar-update-mode-line)
d2e8c33b
RS
106 (calendar-cursor-to-visible-date today)))
107 (run-hooks 'calendar-move-hook))
0808d911 108
6c1841ba 109;;;###cal-autoload
0808d911
ER
110(defun calendar-forward-month (arg)
111 "Move the cursor forward ARG months.
112Movement is backward if ARG is negative."
113 (interactive "p")
114 (calendar-cursor-to-nearest-date)
115 (let* ((cursor-date (calendar-cursor-to-date t))
e803eab7
GM
116 (month (calendar-extract-month cursor-date))
117 (day (calendar-extract-day cursor-date))
118 (year (calendar-extract-year cursor-date))
b36e906d 119 (last (progn
e803eab7 120 (calendar-increment-month month year arg)
b36e906d
GM
121 (calendar-last-day-of-month month year)))
122 (day (min last day))
123 ;; Put the new month on the screen, if needed, and go to the new date.
124 (new-cursor-date (list month day year)))
125 (if (not (calendar-date-is-visible-p new-cursor-date))
126 (calendar-other-month month year))
127 (calendar-cursor-to-visible-date new-cursor-date))
d2e8c33b 128 (run-hooks 'calendar-move-hook))
0808d911 129
6c1841ba 130;;;###cal-autoload
0808d911
ER
131(defun calendar-forward-year (arg)
132 "Move the cursor forward by ARG years.
133Movement is backward if ARG is negative."
134 (interactive "p")
135 (calendar-forward-month (* 12 arg)))
136
6c1841ba 137;;;###cal-autoload
0808d911
ER
138(defun calendar-backward-month (arg)
139 "Move the cursor backward by ARG months.
140Movement is forward if ARG is negative."
141 (interactive "p")
142 (calendar-forward-month (- arg)))
143
6c1841ba 144;;;###cal-autoload
0808d911
ER
145(defun calendar-backward-year (arg)
146 "Move the cursor backward ARG years.
147Movement is forward is ARG is negative."
148 (interactive "p")
149 (calendar-forward-month (* -12 arg)))
150
6c1841ba 151;;;###cal-autoload
ab895089 152(defun calendar-scroll-left (&optional arg event)
0808d911
ER
153 "Scroll the displayed calendar left by ARG months.
154If ARG is negative the calendar is scrolled right. Maintains the relative
db940e42
GM
155position of the cursor with respect to the calendar as well as possible.
156EVENT is an event like `last-nonmenu-event'."
ab895089
SM
157 (interactive (list (prefix-numeric-value current-prefix-arg)
158 last-nonmenu-event))
f7b37bae 159 (unless arg (setq arg 1))
ab895089 160 (save-selected-window
b2cbe2af
GM
161 ;; Nil if called from menu-bar.
162 (if (setq event (event-start event)) (select-window (posn-window event)))
ab895089 163 (calendar-cursor-to-nearest-date)
cfcc468f
GM
164 (unless (zerop arg)
165 (let ((old-date (calendar-cursor-to-date))
166 (today (calendar-current-date))
167 (month displayed-month)
168 (year displayed-year))
e803eab7
GM
169 (calendar-increment-month month year arg)
170 (calendar-generate-window month year)
cfcc468f
GM
171 (calendar-cursor-to-visible-date
172 (cond
173 ((calendar-date-is-visible-p old-date) old-date)
174 ((calendar-date-is-visible-p today) today)
175 (t (list month 1 year))))))
ab895089
SM
176 (run-hooks 'calendar-move-hook)))
177
cfcc468f
GM
178(define-obsolete-function-alias
179 'scroll-calendar-left 'calendar-scroll-left "23.1")
180
6c1841ba 181;;;###cal-autoload
ab895089 182(defun calendar-scroll-right (&optional arg event)
0808d911
ER
183 "Scroll the displayed calendar window right by ARG months.
184If ARG is negative the calendar is scrolled left. Maintains the relative
db940e42
GM
185position of the cursor with respect to the calendar as well as possible.
186EVENT is an event like `last-nonmenu-event'."
ab895089
SM
187 (interactive (list (prefix-numeric-value current-prefix-arg)
188 last-nonmenu-event))
189 (calendar-scroll-left (- (or arg 1)) event))
0808d911 190
cfcc468f
GM
191(define-obsolete-function-alias
192 'scroll-calendar-right 'calendar-scroll-right "23.1")
193
6c1841ba 194;;;###cal-autoload
3309a9ee 195(defun calendar-scroll-left-three-months (arg &optional event)
0808d911
ER
196 "Scroll the displayed calendar window left by 3*ARG months.
197If ARG is negative the calendar is scrolled right. Maintains the relative
3309a9ee
GM
198position of the cursor with respect to the calendar as well as possible.
199EVENT is an event like `last-nonmenu-event'."
200 (interactive (list (prefix-numeric-value current-prefix-arg)
201 last-nonmenu-event))
202 (calendar-scroll-left (* 3 arg) event))
0808d911 203
cfcc468f
GM
204(define-obsolete-function-alias 'scroll-calendar-left-three-months
205 'calendar-scroll-left-three-months "23.1")
206
3f0f1700
GM
207;; cf scroll-bar-toolkit-scroll
208;;;###cal-autoload
209(defun calendar-scroll-toolkit-scroll (event)
210 "Function to scroll the calendar after a toolkit scroll-bar click."
211 (interactive "e")
212 (let ((part (nth 4 (event-end event))))
213 ;; Not bothering with drag events (handle, end-scroll).
214 (cond ((memq part '(above-handle up top))
215 (calendar-scroll-right nil event))
216 ((memq part '(below-handle down bottom))
217 (calendar-scroll-left nil event)))))
218
6c1841ba 219;;;###cal-autoload
3309a9ee 220(defun calendar-scroll-right-three-months (arg &optional event)
0808d911
ER
221 "Scroll the displayed calendar window right by 3*ARG months.
222If ARG is negative the calendar is scrolled left. Maintains the relative
3309a9ee
GM
223position of the cursor with respect to the calendar as well as possible.
224EVENT is an event like `last-nonmenu-event'."
225 (interactive (list (prefix-numeric-value current-prefix-arg)
226 last-nonmenu-event))
227 (calendar-scroll-left (* -3 arg) event))
0808d911 228
cfcc468f
GM
229(define-obsolete-function-alias 'scroll-calendar-right-three-months
230 'calendar-scroll-right-three-months "23.1")
0808d911 231
6c1841ba 232;;;###cal-autoload
0808d911
ER
233(defun calendar-forward-day (arg)
234 "Move the cursor forward ARG days.
235Moves backward if ARG is negative."
236 (interactive "p")
cfcc468f
GM
237 (unless (zerop arg)
238 (let* ((cursor-date (or (calendar-cursor-to-date)
239 (progn
240 (if (> arg 0) (setq arg (1- arg)))
241 (calendar-cursor-to-nearest-date))))
0808d911
ER
242 (new-cursor-date
243 (calendar-gregorian-from-absolute
244 (+ (calendar-absolute-from-gregorian cursor-date) arg)))
e803eab7
GM
245 (new-display-month (calendar-extract-month new-cursor-date))
246 (new-display-year (calendar-extract-year new-cursor-date)))
d5a8ed10
GM
247 ;; Put the new month on the screen, if needed.
248 (unless (calendar-date-is-visible-p new-cursor-date)
3eee90de
GM
249 ;; The next line gives smoother scrolling IMO (one month at a
250 ;; time rather than two).
251 (calendar-increment-month new-display-month new-display-year
252 (if (< arg 0) 1 -1))
d5a8ed10
GM
253 (calendar-other-month new-display-month new-display-year))
254 ;; Go to the new date.
255 (calendar-cursor-to-visible-date new-cursor-date)))
d2e8c33b 256 (run-hooks 'calendar-move-hook))
0808d911 257
6c1841ba 258;;;###cal-autoload
0808d911
ER
259(defun calendar-backward-day (arg)
260 "Move the cursor back ARG days.
261Moves forward if ARG is negative."
262 (interactive "p")
263 (calendar-forward-day (- arg)))
264
6c1841ba 265;;;###cal-autoload
0808d911
ER
266(defun calendar-forward-week (arg)
267 "Move the cursor forward ARG weeks.
268Moves backward if ARG is negative."
269 (interactive "p")
270 (calendar-forward-day (* arg 7)))
271
6c1841ba 272;;;###cal-autoload
0808d911
ER
273(defun calendar-backward-week (arg)
274 "Move the cursor back ARG weeks.
275Moves forward if ARG is negative."
276 (interactive "p")
277 (calendar-forward-day (* arg -7)))
278
6c1841ba 279;;;###cal-autoload
0808d911
ER
280(defun calendar-beginning-of-week (arg)
281 "Move the cursor back ARG calendar-week-start-day's."
282 (interactive "p")
283 (calendar-cursor-to-nearest-date)
284 (let ((day (calendar-day-of-week (calendar-cursor-to-date))))
285 (calendar-backward-day
286 (if (= day calendar-week-start-day)
287 (* 7 arg)
288 (+ (mod (- day calendar-week-start-day) 7)
289 (* 7 (1- arg)))))))
290
6c1841ba 291;;;###cal-autoload
0808d911
ER
292(defun calendar-end-of-week (arg)
293 "Move the cursor forward ARG calendar-week-start-day+6's."
294 (interactive "p")
295 (calendar-cursor-to-nearest-date)
296 (let ((day (calendar-day-of-week (calendar-cursor-to-date))))
297 (calendar-forward-day
298 (if (= day (mod (1- calendar-week-start-day) 7))
299 (* 7 arg)
300 (+ (- 6 (mod (- day calendar-week-start-day) 7))
301 (* 7 (1- arg)))))))
302
6c1841ba 303;;;###cal-autoload
0808d911
ER
304(defun calendar-beginning-of-month (arg)
305 "Move the cursor backward ARG month beginnings."
306 (interactive "p")
307 (calendar-cursor-to-nearest-date)
308 (let* ((date (calendar-cursor-to-date))
e803eab7
GM
309 (month (calendar-extract-month date))
310 (day (calendar-extract-day date))
311 (year (calendar-extract-year date)))
0808d911
ER
312 (if (= day 1)
313 (calendar-backward-month arg)
314 (calendar-cursor-to-visible-date (list month 1 year))
315 (calendar-backward-month (1- arg)))))
316
6c1841ba 317;;;###cal-autoload
0808d911
ER
318(defun calendar-end-of-month (arg)
319 "Move the cursor forward ARG month ends."
320 (interactive "p")
321 (calendar-cursor-to-nearest-date)
322 (let* ((date (calendar-cursor-to-date))
e803eab7
GM
323 (month (calendar-extract-month date))
324 (day (calendar-extract-day date))
325 (year (calendar-extract-year date))
b36e906d
GM
326 (last-day (calendar-last-day-of-month month year))
327 (last-day (progn
328 (unless (= day last-day)
329 (calendar-cursor-to-visible-date
330 (list month last-day year))
331 (setq arg (1- arg)))
e803eab7 332 (calendar-increment-month month year arg)
b36e906d
GM
333 (list month
334 (calendar-last-day-of-month month year)
335 year))))
336 (if (not (calendar-date-is-visible-p last-day))
337 (calendar-other-month month year)
338 (calendar-cursor-to-visible-date last-day)))
d2e8c33b 339 (run-hooks 'calendar-move-hook))
0808d911 340
6c1841ba 341;;;###cal-autoload
0808d911
ER
342(defun calendar-beginning-of-year (arg)
343 "Move the cursor backward ARG year beginnings."
344 (interactive "p")
345 (calendar-cursor-to-nearest-date)
346 (let* ((date (calendar-cursor-to-date))
e803eab7
GM
347 (month (calendar-extract-month date))
348 (day (calendar-extract-day date))
349 (year (calendar-extract-year date))
d2e8c33b
RS
350 (jan-first (list 1 1 year))
351 (calendar-move-hook nil))
0808d911
ER
352 (if (and (= day 1) (= 1 month))
353 (calendar-backward-month (* 12 arg))
354 (if (and (= arg 1)
355 (calendar-date-is-visible-p jan-first))
356 (calendar-cursor-to-visible-date jan-first)
25b11e01
GM
357 (calendar-other-month 1 (- year (1- arg)))
358 (calendar-cursor-to-visible-date (list 1 1 displayed-year)))))
d2e8c33b 359 (run-hooks 'calendar-move-hook))
0808d911 360
6c1841ba 361;;;###cal-autoload
0808d911
ER
362(defun calendar-end-of-year (arg)
363 "Move the cursor forward ARG year beginnings."
364 (interactive "p")
365 (calendar-cursor-to-nearest-date)
366 (let* ((date (calendar-cursor-to-date))
e803eab7
GM
367 (month (calendar-extract-month date))
368 (day (calendar-extract-day date))
369 (year (calendar-extract-year date))
d2e8c33b
RS
370 (dec-31 (list 12 31 year))
371 (calendar-move-hook nil))
0808d911
ER
372 (if (and (= day 31) (= 12 month))
373 (calendar-forward-month (* 12 arg))
374 (if (and (= arg 1)
375 (calendar-date-is-visible-p dec-31))
376 (calendar-cursor-to-visible-date dec-31)
25b11e01 377 (calendar-other-month 12 (+ year (1- arg)))
d2e8c33b
RS
378 (calendar-cursor-to-visible-date (list 12 31 displayed-year)))))
379 (run-hooks 'calendar-move-hook))
0808d911 380
6c1841ba 381;;;###cal-autoload
0808d911
ER
382(defun calendar-goto-date (date)
383 "Move cursor to DATE."
384 (interactive (list (calendar-read-date)))
e803eab7
GM
385 (let ((month (calendar-extract-month date))
386 (year (calendar-extract-year date)))
0808d911
ER
387 (if (not (calendar-date-is-visible-p date))
388 (calendar-other-month
389 (if (and (= month 1) (= year 1))
390 2
391 month)
392 year)))
d2e8c33b
RS
393 (calendar-cursor-to-visible-date date)
394 (run-hooks 'calendar-move-hook))
0808d911 395
6c1841ba 396;;;###cal-autoload
163fd24d 397(defun calendar-goto-day-of-year (year day &optional noecho)
cfcc468f 398 "Move cursor to YEAR, DAY number; echo DAY/YEAR unless NOECHO is non-nil.
163fd24d
GM
399Negative DAY counts backward from end of year."
400 (interactive
401 (let* ((year (calendar-read
402 "Year (>0): "
403 (lambda (x) (> x 0))
d92bcf94 404 (number-to-string (calendar-extract-year
163fd24d
GM
405 (calendar-current-date)))))
406 (last (if (calendar-leap-year-p year) 366 365))
407 (day (calendar-read
408 (format "Day number (+/- 1-%d): " last)
5942f9af 409 (lambda (x) (and (<= 1 (abs x)) (<= (abs x) last))))))
163fd24d
GM
410 (list year day)))
411 (calendar-goto-date
412 (calendar-gregorian-from-absolute
413 (if (< 0 day)
414 (+ -1 day (calendar-absolute-from-gregorian (list 1 1 year)))
415 (+ 1 day (calendar-absolute-from-gregorian (list 12 31 year))))))
416 (or noecho (calendar-print-day-of-year)))
417
0808d911
ER
418(provide 'cal-move)
419
420;;; cal-move.el ends here