+(defcustom calendar-date-echo-text
+ "mouse-2: general menu\nmouse-3: menu for this date"
+ "String displayed when the cursor is over a date in the calendar.
+Can be either a fixed string, or a lisp expression that returns one.
+When this expression is evaluated, DAY, MONTH, and YEAR are
+integers appropriate to the relevant date. For example, to
+display the ISO date:
+
+ (setq calendar-date-echo-text '(format \"ISO date: %s\"
+ (calendar-iso-date-string
+ (list month day year))))
+Changing this variable without using customize has no effect on
+pre-existing calendar windows."
+ :group 'calendar
+ :initialize 'custom-initialize-default
+ :risky t
+ :set (lambda (sym val)
+ (set sym val)
+ (calendar-redraw))
+ :type '(choice (string :tag "Fixed string")
+ (sexp :value
+ (format "ISO date: %s"
+ (calendar-iso-date-string
+ (list month day year)))))
+ :version "23.1")
+
+
+(defvar calendar-month-digit-width nil
+ "Width of the region with numbers in each month in the calendar.")
+
+(defvar calendar-month-width nil
+ "Full width of each month in the calendar.")
+
+(defvar calendar-right-margin nil
+ "Right margin of the calendar.")
+
+(defvar calendar-month-edges nil
+ "Alist of month edge columns.
+Each element has the form (N LEFT FIRST LAST RIGHT), where
+LEFT is the leftmost column associated with month segment N,
+FIRST and LAST are the first and last columns with day digits in,
+and LAST is the rightmost column.")
+
+(defun calendar-month-edges (segment)
+ "Compute the month edge columns for month SEGMENT.
+Returns a list (LEFT FIRST LAST RIGHT), where LEFT is the
+leftmost column associated with a month, FIRST and LAST are the
+first and last columns with day digits in, and LAST is the
+rightmost column."
+ ;; The leftmost column with a digit in it in this month segment.
+ (let* ((first (+ calendar-left-margin
+ (* segment calendar-month-width)))
+ ;; The rightmost column with a digit in it in this month segment.
+ (last (+ first (1- calendar-month-digit-width)))
+ (left (if (eq segment 0)
+ 0
+ (+ calendar-left-margin
+ (* segment calendar-month-width)
+ (- (/ calendar-intermonth-spacing 2)))))
+ ;; The rightmost edge of this month segment, dividing the
+ ;; space between months in two.
+ (right (+ calendar-left-margin
+ (* (1+ segment) calendar-month-width)
+ (- (/ calendar-intermonth-spacing 2)))))
+ (list left first last right)))
+
+(defun calendar-recompute-layout-variables ()
+ "Recompute some layout-related calendar \"constants\"."
+ (setq calendar-month-digit-width (+ (* 6 calendar-column-width)
+ calendar-day-digit-width)
+ calendar-month-width (+ (* 7 calendar-column-width)
+ calendar-intermonth-spacing)
+ calendar-right-margin (+ calendar-left-margin
+ (* 3 (* 7 calendar-column-width))
+ (* 2 calendar-intermonth-spacing))
+ calendar-month-edges nil)
+ (dotimes (i 3)
+ (push (cons i (calendar-month-edges i)) calendar-month-edges))
+ (setq calendar-month-edges (reverse calendar-month-edges)))
+
+;; FIXME add font-lock-keywords.
+(defun calendar-set-layout-variable (symbol value &optional minmax)
+ "Set SYMBOL's value to VALUE, an integer.
+A positive/negative MINMAX enforces a minimum/maximum value.
+Then redraw the calendar, if necessary."
+ (let ((oldvalue (symbol-value symbol)))
+ (custom-set-default symbol (if minmax
+ (if (< minmax 0)
+ (min value (- minmax))
+ (max value minmax))
+ value))
+ (unless (equal value oldvalue)
+ (calendar-recompute-layout-variables)
+ (calendar-redraw))))
+
+(defcustom calendar-left-margin 5
+ "Empty space to the left of the first month in the calendar."
+ :group 'calendar
+ :initialize 'custom-initialize-default
+ :set 'calendar-set-layout-variable
+ :type 'integer
+ :version "23.1")
+
+;; Or you can view it as columns of width 2, with 1 space, no space
+;; after the last column, and a 5 space gap between month.
+;; FIXME check things work if this is odd.
+(defcustom calendar-intermonth-spacing 4
+ "Space between months in the calendar. Minimum value is 1."
+ :group 'calendar
+ :initialize 'custom-initialize-default
+ :set (lambda (sym val)
+ (calendar-set-layout-variable sym val 1))
+ :type 'integer
+ :version "23.1")
+
+;; FIXME calendar-month-column-width?
+(defcustom calendar-column-width 3
+ "Width of each day column in the calendar. Minimum value is 3."
+ :initialize 'custom-initialize-default
+ :set (lambda (sym val)
+ (calendar-set-layout-variable sym val 3))
+ :type 'integer
+ :version "23.1")
+
+(defcustom calendar-day-header-width 2
+ "Width of the day column headers in the calendar.
+Must be at least one less than `calendar-column-width'."
+ :group 'calendar
+ :initialize 'custom-initialize-default
+ :set (lambda (sym val)
+ (calendar-set-layout-variable sym val (- 1 calendar-column-width)))
+ :type 'integer
+ :version "23.1")
+
+;; FIXME a format specifier instead?
+(defcustom calendar-day-digit-width 2
+ "Width of the day digits in the calendar. Minimum value is 2."
+ :group 'calendar
+ :initialize 'custom-initialize-default
+ :set (lambda (sym val)
+ (calendar-set-layout-variable sym val 2))
+ :type 'integer
+ :version "23.1")
+
+(defcustom calendar-intermonth-header nil
+ "Header text display in the space to the left of each calendar month.
+See `calendar-intermonth-text'."
+ :group 'calendar
+ :initialize 'custom-initialize-default
+ :risky t
+ :set (lambda (sym val)
+ (set sym val)
+ (calendar-redraw))
+ :type '(choice (const nil :tag "Nothing")
+ (string :tag "Fixed string")
+ (sexp :value
+ (propertize "WK" 'font-lock-face
+ 'font-lock-function-name-face)))
+ :version "23.1")
+
+(defcustom calendar-intermonth-text nil
+ "Text to display in the space to the left of each calendar month.
+Can be nil, a fixed string, or a lisp expression that returns a string.
+When the expression is evaluated, the variables DAY, MONTH and YEAR
+are integers appropriate for the first day in each week.
+Will be truncated to the smaller of `calendar-left-margin' and
+`calendar-intermonth-spacing'. The last character is forced to be a space.
+For example, to display the ISO week numbers:
+
+ (setq calendar-week-start-day 1
+ calendar-intermonth-text
+ '(propertize
+ (format \"%2d\"
+ (car
+ (calendar-iso-from-absolute
+ (calendar-absolute-from-gregorian (list month day year)))))
+ 'font-lock-face 'font-lock-function-name-face))
+
+See also `calendar-intermonth-header'."
+ :group 'calendar
+ :initialize 'custom-initialize-default
+ :risky t
+ :set (lambda (sym val)
+ (set sym val)
+ (calendar-redraw))
+ :type '(choice (const nil :tag "Nothing")
+ (string :tag "Fixed string")
+ (sexp :value
+ (propertize
+ (format "%2d"
+ (car
+ (calendar-iso-from-absolute
+ (calendar-absolute-from-gregorian
+ (list month day year)))))
+ 'font-lock-face 'font-lock-function-name-face)))
+ :version "23.1")
+