; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
; Revision: January 2012 - added Hungarian translation (thanks to petrikp)
; March 2012 - added Polish (thanks to Mario)
; January 2013 - added Russian translation (thanks to Leonid)
; January 2013 - Serbian, Croatian, Slovenian, Macedonian (thanks to Skynet)
; March 2013 - Swedish (thanks to Ullis)
; April 2015 - Catalan (thanks to Xavier)
; 'layout'
; 0 = Allow week 6
; 1 = Force week 6
; 2 = Wrap w6 to w1
; 3 = Wrap w6 to w5
(define sg-calendar-languages '("English" "German" "Italian" "Spanish"
"French" "Hungarian" "Polish" "Russian"
"Serbian latin" "Serbian cyrilic" "Croatian" "Slovenian"
"Macedonian" "Swedish" "Catalan") )
;; Each of the following translations are comprised of a list of:
;; (months) (days) (day-abbreviations)
;; If the day-abbreviations is #f then the letters-in-day parameter is
;; used to generate the abbreviation from the full day name.
;;
;; Languages appear in the order that they were contributed.
;;
(define sg-calendar-translations
'(( ; "English"
("January" "February" "March" "April"
"May" "June" "July" "August"
"September" "October" "November" "December")
("Monday" "Tuesday" "Wednesday" "Thursday"
"Friday" "Saturday" "Sunday")
#f)
( ; "German"
("Januar" "Februar" "März" "April"
"Mai" "Juni" "Juli" "August"
"September" "Oktober" "November" "Dezember")
("Montag" "Dienstag" "Mittwoch" "Donnerstag"
"Freitag" "Samstag" "Sonntag")
#f)
( ; "Italian"
("Gennaio" "Febbraio" "Marzo" "Aprile"
"Maggio" "Giugno" "Luglio" "Agosto"
"Settembre" "Ottobre" "Novembre" "Dicembre")
("Lunedi" "Martedi" "Mercoledi" "Giovedi"
"Venerdi" "Sabato" "Domenica")
#f)
( ; "Spanish"
("Enero" "Febrero" "Marzo" "Abril"
"Mayo" "Junio" "Julio" "Agosto"
"Septiembre" "Octubre" "Noviembre" "Diciembre")
("Lunes" "Martes" "Miercoles" "Jueves"
"Viernes" "Sabado" "Domingo")
#f)
( ; "French"
("Janvier" "Février" "Mars" "Avril"
"Mai" "Juin" "Juillet" "Août"
"Septembre" "Octobre" "Novembre" "Décembre")
("Lundi" "Mardi" "Mercredi" "Jeudi"
"Vendredi" "Samedi" "Dimanche")
#f)
( ; "Hungarian"
("Január" "Február" "Március" "Április"
"Május" "Június" "Július" "Augusztus"
"Szeptember" "Október" "November" "December")
("vasárnap" "hétfő" "kedd" "szerda"
"csütörtök" "péntek" "szombat")
#f)
( ; "Polish"
("Styczeń" "Luty" "Marzec" "Kwiecień"
"Maj" "Czerwiec" "Lipiec" "Sierpień"
"Wrzesień" "Październik" "Listopad" "Grudzień")
("Poniedziałek" "Wtorek" "Środa" "Czwartek"
"Piątek" "Sobota" "Niedziela")
#f)
( ; "Russian"
("Январь" "Февраль" "Март" "Апрель"
"Май" "Июнь" "Июль" "Август"
"Сентябрь" "Октябрь" "Ноябрь" "Декабрь")
("Понедельник" "Вторник" "Среда" "Четверг"
"Пятница" "Суббота" "Воскресенье")
#f)
( ; "Serbian latin"
("Januar" "Februar" "Mart" "April"
"Maj" "Jun" "Jul" "Avgust"
"Septembar" "Oktobar" "Novembar" "Decembar")
("Ponedeljak" "Utorak" "Sreda" "Četvrtak"
"Petak" "Subota" "Nedelja")
#f)
( ; "Serbian cyrilic"
("Јануар" "Фебруар" "Март" "Април"
"Мај" "Јун" "Јул" "Август"
"Септембар" "Октобар" "Новембар" "Децембар")
("Понедељак" "Уторак" "Среда" "Четвртак"
"Петак" "Субота" "Недеља")
#f)
( ; "Croatian"
("Siječanj" "Veljača" "Ožujak" "Travanj"
"Svibanj" "Lipanj" "Srpanj" "Kolovoz"
"Rujan" "Listopad" "Studeni" "Prosinac")
("Ponedjeljak" "Utorak" "Srijeda" "Četvrtak"
"Petak" "Subota" "Nedjelja")
#f)
( ; "Slovenian"
("Januar" "Februar" "Marec" "April"
"Maj" "Junij" "Julij" "Avgust"
"September" "Oktober" "November" "December")
("Ponedeljek" "Torek" "Sreda" "Četrtek"
"Petek" "Sobota" "Nedelja")
#f)
( ; "Macedonian"
("Коложег" "Сечко" "Цутар" "Тревен"
"Косар" "Жетвар" "Златец" "Житар"
"Гроздобер" "Листопад" "Студен" "Снежник")
("Понеделник" "Вторник" "Среда" "Четврток"
"Петок" "Сабота" "Недела")
#f)
( ; "Swedish"
("Januari" "Februari" "Mars" "April"
"Maj" "Juni" "Juli" "Augusti"
"September" "Oktober" "November" "December")
("Måndag" "Tisdag" "Onsdag" "Torsdag"
"Fredag" "Lördag" "Söndag")
#f)
( ; "Catalan"
("Gener" "Febrer" "Març" "Abril"
"Maig" "Juny" "Juliol" "Agost"
"Setembre" "Octubre" "Novembre" "Desembre")
("Dilluns" "Dimarts" "Dimecres" "Dijous"
"Divendres" "Dissabte" "Diumenge")
("DL" "DT" "DC" "DJ" "DV" "DS" "DG"))
))
;; Perform a crude search for the largest font that will fit within
;; the cell (this algorithm could be better!)
;
(define (sg-calendar-calc-fontsize text font fontsize% width height)
(let* ((fontsize 6) ;; minimum possible fontsize
(extents nil)
(last-extents nil)
(last-fontsize 3)
(adjust 2) )
(set! extents (gimp-text-get-extents-fontname text fontsize PIXELS font))
(set! width (* width fontsize% 0.01))
(set! height (* height fontsize% 0.01))
(while (and (<> last-fontsize fontsize) (not (equal? extents last-extents)))
(if (or (> (car extents) width) (> (cadr extents) height))
(begin
(set! fontsize last-fontsize)
(set! adjust (+ (* (- adjust 1) 0.5) 1)) )
(begin
(set! last-extents extents)
(set! last-fontsize fontsize) ) )
(set! fontsize (truncate (* fontsize adjust)))
(set! extents (gimp-text-get-extents-fontname text fontsize PIXELS font)) )
(max fontsize 6) ) )
(define (script-fu-sg-calendar image drawable lang month year sunday?
letters-in-day layout text-font number-font
fontsize% justify? border border-color gravity)
;; 'leap-year' returns one if given year is a leap year, else zero
;
(define (leap-year yy)
(if (= (modulo yy 4) 0)
(if (or (> (modulo yy 100) 0) (= (modulo yy 400) 0))
1
0 )
0 ) )
;; Given a Gregorian date, the following computes the number of days that have elapsed since
;; March 1st, 0000. This date is chosen as an absolute reference
;; so that leap days occur at the "end of the year" (simplifying
;; calculations). For lack of a better name, I shall call this a
;; "martius date" after the Roman word for the month of March.
;
(define (gregorian->martius yy mm dd)
(set! mm (modulo (+ mm 9) 12))
(set! yy (- yy (truncate (/ mm 10))))
(inexact->exact (+ (trunc (* 365 yy))
(trunc (/ yy 4))
(- (trunc (/ yy 100)))
(trunc (/ yy 400))
(round (* mm 30.6)) dd -1 )) )
;; Given a Gregorian date, return the day of the week (0=Sunday, 1=Monday,...)
;
(define (day-of-week yy mm dd)
(modulo (+ (gregorian->martius yy mm dd) 3) 7) )
;; The following converts from an absolute number of days since
;; March 1st, 0000 (i.e., a "martius date") to a Gregorian date
;; A list is returned containing '(year month day)
;
(define (martius->gregorian mdays)
(let* ((yy 0)
(mm 0)
(mi 0)
(dd 0) )
(set! yy (truncate (+ (/ mdays 365.2425) (/ 1.4780 365.2425))))
(set! dd (- mdays (truncate (* yy 365.2425))))
(when (< dd 0)
(set! yy (- yy 1))
(set! dd (- mdays (truncate (* yy 365.2425)))) )
(set! mi (inexact->exact (truncate (/ (+ 0.52 dd) 30.60))))
(set! mm (+ (modulo (+ mi 2) 12) 1))
(set! yy (+ yy (truncate (/ (+ mi 2) 12))))
(set! dd (+ (- dd (round (* mi 30.6))) 1))
(list yy mm dd) ) )
;; Create a list of floats evenly distributed between start and end
;
(define (algebraic-prog start end elements)
(let ((elements (inexact->exact elements))
(incr (if (zero? start)
(/ end (- elements 1))
(/ (- (/ end start) 1) (- elements 1)) ) ) )
(let
loop ((cnt (- elements 1))
(lis (if (zero? start)
'(0)
'(1) ) ) )
(if (zero? cnt)
(if (zero? start)
(reverse lis)
(map * (reverse lis) (make-list elements start)) )
(loop (- cnt 1) (cons (+ (car lis) incr) lis)) ) ) ) )
;; Create a frame layer for a cell
;
(define (create-cell-frame x y w h)
(let* ((frame-layer (car (gimp-layer-new image
w h
RGBA-IMAGE "Cell #1"
100 NORMAL-MODE ))) )
(gimp-drawable-fill frame-layer TRANSPARENT-FILL)
(gimp-image-add-layer image frame-layer -1)
(gimp-layer-set-offsets frame-layer x y)
(gimp-rect-select image (+ x border) (+ y border) (- w (* 2 border)) (- h (* 2 border)) CHANNEL-OP-REPLACE FALSE 0)
(gimp-selection-invert image)
(gimp-context-set-background border-color)
(gimp-edit-fill frame-layer BACKGROUND-FILL)
(gimp-selection-none image)
frame-layer ) )
;; Create the text layer for a cell-frame
;
(define (create-cell-text text font fontsize gravity frame-layer)
(let* ((text-layer (car (gimp-text-fontname image -1
0 0
text (* 2 border)
TRUE fontsize
PIXELS font )))
(x-align 0)
(y-align 0) )
(if (or (= gravity 0) (= gravity 1) (= gravity 2))
(set! y-align -1)
(when (or (= gravity 6) (= gravity 7) (= gravity 8))
(set! y-align 1) ) )
(if (or (= gravity 0) (= gravity 3) (= gravity 6))
(set! x-align -1)
(when (or (= gravity 2) (= gravity 5) (= gravity 8))
(set! x-align 1) ) )
(fu-align-layers frame-layer text-layer x-align y-align)
text-layer
)
)
;; align layer(s) with a base-layer (layers can be either a single layer or a list of layers)
;; vert-align and horiz-align
;; -1 = LEFT, 0 = CENTER, 1 = RIGHT
;
(define (fu-align-layers base-layer layers vert-align horiz-align)
(let* ((anchor-x (car (gimp-drawable-offsets base-layer)))
(anchor-y (cadr (gimp-drawable-offsets base-layer)))
(width (car (gimp-drawable-width base-layer)))
(height (car (gimp-drawable-height base-layer))) )
(unless (pair? layers)
(set! layers (list layers)) )
(if (>= vert-align 0)
(if (= vert-align 0)
(set! anchor-x (+ anchor-x (/ width 2)))
(set! anchor-x (+ anchor-x width)) ) )
(if (>= horiz-align 0)
(if (= horiz-align 0)
(set! anchor-y (+ anchor-y (/ height 2)))
(set! anchor-y (+ anchor-y height)) ) )
(while (pair? layers)
(let* (
(layer (car layers))
(ref-x (car (gimp-drawable-offsets layer)))
(ref-y (cadr (gimp-drawable-offsets layer)))
(orig-x ref-x)
(orig-y ref-y)
(offset-x 0)
(offset-y 0)
)
(set! width (car (gimp-drawable-width layer)))
(set! height (car (gimp-drawable-height layer)))
(if (>= vert-align 0)
(if (= vert-align 0)
(set! ref-x (+ ref-x (/ width 2)))
(set! ref-x (+ ref-x width))
)
)
(if (>= horiz-align 0)
(if (= horiz-align 0)
(set! ref-y (+ ref-y (/ height 2)))
(set! ref-y (+ ref-y height))
)
)
(set! offset-x (+ orig-x (- anchor-x ref-x)))
(set! offset-y (+ orig-y (- anchor-y ref-y)))
(gimp-layer-set-offsets layer offset-x offset-y)
)
(set! layers (cdr layers))
)
)
)
;; return a list of visible layers
;
(define (fu-get-visible-layers image)
(let loop ((layers (vector->list (cadr (gimp-image-get-layers image))))
(viewables nil) )
(if (null? layers)
(if (null? viewables)
'()
(reverse viewables) )
(loop (cdr layers)
(if (zero? (car (gimp-drawable-get-visible (car layers))))
viewables
(cons (car layers) viewables) ) ) ) ) )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Main definition starts here ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(let* ((bg-layer 0)
(x1 0)
(x2 0)
(y1 0)
(y2 0)
(X's '())
(Y's '())
(x's '())
(y's '())
(row 0)
(total-rows 6)
(col 0)
(text-fontsize 6)
(number-fontsize 6)
(firstday (day-of-week year (+ month 1) 1))
(days-in-month (vector 31 (+ 28 (leap-year year)) 31 30 31 30 31 31 30 31 30 31))
(i 0)
(frames nil)
(frame-layer 0)
(cal-days nil)
(dates-layer 0)
(visibles '())
(buffer "")
(layers nil)
(orig-bg (car (gimp-context-get-background)))
(orig-sel 0)
(months (list->vector (car (list-ref sg-calendar-translations lang))))
(weekday-strings (list->vector (cond
((caddr (list-ref sg-calendar-translations lang)))
(else
(map (lambda (x)
(substring x
0
(min (+ letters-in-day 1)
(string-length x))))
(cadr (list-ref sg-calendar-translations
lang)))))))
)
(gimp-context-push)
(gimp-image-undo-group-start image)
(set! orig-sel (car (gimp-selection-save image)))
(set! buffer (car (gimp-edit-named-copy drawable "buffer")))
(set! bg-layer (car (gimp-edit-named-paste drawable buffer FALSE)))
(gimp-floating-sel-to-layer bg-layer)
(gimp-buffer-delete buffer)
(let loop ((pos (- (car (gimp-image-get-layer-position image drawable)) 1)))
(if (zero? pos)
#t
(begin
(gimp-image-lower-layer image bg-layer)
(loop (- pos 1)) )))
(set! x1 (+ border (car (gimp-drawable-offsets bg-layer))))
(set! x2 (- (+ x1 (car (gimp-drawable-width bg-layer))) (* 2 border)))
(set! y1 (+ border (cadr (gimp-drawable-offsets bg-layer))))
(set! y2 (- (+ y1 (car (gimp-drawable-height bg-layer))) (* 2 border)))
(set! X's (map round (algebraic-prog x1 x2 8)))
(set! Y's (map round (algebraic-prog y1 y2 7))) ;; 1 row for header + five rows for weeks
(set! x's X's)
(set! y's Y's)
(set! visibles (fu-get-visible-layers image))
(unless (= sunday? TRUE)
(set! firstday (modulo (- firstday 1) 7))
)
(when (or (= layout 1) (and (= layout 0) (> (+ firstday (vector-ref days-in-month month)) 35)))
(set! Y's (map round (algebraic-prog y1 y2 8))) ;; 1 row for header + six rows for weeks
(set! y's Y's)
(set! total-rows 7)
)
;; Add header row with day labels
;; Determine fontsize for days
(set! text-fontsize (apply min (map (lambda (text)
(sg-calendar-calc-fontsize text
text-font
80
(- (cadr X's) (car X's) (* 2 border))
(- (cadr Y's) (car Y's) (* 2 border)) ) )
(vector->list weekday-strings) ) ) )
(gimp-progress-update (/ 1 (* total-rows 7)))
(set! x's X's)
(while (< i 7)
(set! frames (cons (create-cell-frame (car x's) ; cell upper-left x
(car y's) ; cell upper-left y
(round (- (cadr x's) (car x's))) ; width
(round (- (cadr y's) (car y's)))) ; height
frames))
(set! cal-days (cons (create-cell-text (vector-ref weekday-strings (modulo (- i sunday? ) 7))
text-font
text-fontsize
7 ;; center text in cell
(car frames))
cal-days ))
(set! i (+ i 1))
(gimp-progress-update (/ (+ i 1) (* total-rows 7)))
(set! x's (cdr x's))
)
(set! row (+ row 1))
(set! y's (cdr y's))
(set! x's X's)
(set! i 0)
;; Determine fontsize for numbers
(if (< fontsize% 80)
(set! number-fontsize (sg-calendar-calc-fontsize "30" number-font fontsize% (- (cadr X's) (car X's) (* 4 border)) (- (cadr Y's) (car Y's) (* 4 border))))
(set! number-fontsize (sg-calendar-calc-fontsize "30" number-font fontsize% (- (cadr X's) (car X's) (* 2 border)) (- (cadr Y's) (car Y's) (* 2 border))))
)
;; create grid of "cells"
;; grid contains cells for the days
;; Each cell has a transparent layer with optional border and
;; valid days have a text layer holding the day number.
;; the day of the month is "0" if cell is not in month
;;
(if (= layout 2)
(while (> (- (+ firstday (vector-ref days-in-month month)) i) 35)
(set! frames (cons (create-cell-frame (car x's) ; cell upper-left x
(car y's) ; cell upper-left y
(round (- (cadr x's) (car x's))) ; width
(round (- (cadr y's) (car y's)))) ; height
frames))
(let* (
(date (+ (- 36 firstday) i))
(date-str (number->string date))
)
(set! cal-days (cons (create-cell-text date-str number-font number-fontsize gravity (car frames)) cal-days))
)
(set! i (+ i 1))
(gimp-progress-update (/ (+ i 8) (* total-rows 7)))
(set! x's (cdr x's))
(set! col (+ col 1))
)
)
(let* (
(bindle-x (car x's))
)
(while (< i firstday)
(set! i (+ i 1))
(gimp-progress-update (/ (+ i 8) (* total-rows 7)))
(set! x's (cdr x's))
)
(unless (= i col)
(set! frames (cons (create-cell-frame bindle-x ; cell upper-left x
(car y's) ; cell upper-left y
(round (- (car x's) bindle-x)) ; width
(round (- (cadr y's) (car y's)))) ; height
frames))
(set! col i)
)
)
(while (< row total-rows)
(while (and (< col 7) (< i (+ (vector-ref days-in-month month) firstday)))
(set! frames (cons (create-cell-frame (car x's) ; cell upper-left x
(car y's) ; cell upper-left y
(round (- (cadr x's) (car x's))) ; width
(round (- (cadr y's) (car y's)))) ; height
frames))
(let* (
(date (+ (- i firstday) 1))
(date-str (if (and (= justify? TRUE) (< date 10))
(string-append " " (number->string date))
(number->string date)))
(double-day 0)
(cal-day 0)
)
(set! cal-day (create-cell-text date-str number-font number-fontsize gravity (car frames)))
(if (= layout 3) ;; if needed, squeeze two dates into text cell (e.g., 23/30, 24/31)
(when (and (> (+ firstday (vector-ref days-in-month month)) 35)
(= row 5)
(<= (+ date 7) (vector-ref days-in-month month)))
(gimp-edit-clear cal-day)
(set! double-day (create-cell-text date-str number-font (* number-fontsize 0.5) 0 cal-day))
(set! cal-day (car (gimp-image-merge-down image double-day EXPAND-AS-NECESSARY)))
(set! double-day (create-cell-text (number->string (+ date 7)) number-font (* number-fontsize 0.5) 8 cal-day))
(set! cal-day (car (gimp-image-merge-down image double-day EXPAND-AS-NECESSARY)))
)
)
(set! cal-days (cons cal-day cal-days))
)
(set! i (+ i 1))
(gimp-progress-update (/ (+ i 8) (* total-rows 7)))
(set! x's (cdr x's))
(set! col (+ col 1))
)
(unless (or (< i (+ (vector-ref days-in-month month) firstday)) (= col 7))
(let* (
(bindle-x (car x's))
)
(while (< col 7)
(set! i (+ i 1))
(set! x's (cdr x's))
(set! col (+ col 1))
)
(set! frames (cons (create-cell-frame bindle-x ; cell upper-left x
(car y's) ; cell upper-left y
(round (- (car x's) bindle-x)) ; width
(round (- (cadr y's) (car y's)))) ; height
frames))
(set! i (+ i 1))
(set! x's (cdr x's))
(set! col (+ col 1))
(if (= col 7)
(set! col 0)
)
)
)
(set! row (+ row 1))
(set! col 0)
(set! x's X's)
(set! y's (cdr y's))
)
(gimp-image-set-active-layer image bg-layer)
(set! frame-layer (car (gimp-layer-new-from-drawable bg-layer image)))
(gimp-image-add-layer image frame-layer -1)
(gimp-layer-add-alpha frame-layer)
(gimp-selection-none image)
(gimp-edit-clear frame-layer)
(gimp-context-set-background border-color)
(gimp-rect-select image x1 y1 (round (- x2 x1)) (round (- y2 y1)) CHANNEL-OP-REPLACE FALSE 0)
(gimp-selection-invert image)
(unless (= border 0)
(gimp-edit-fill frame-layer BACKGROUND-FILL)
)
(map (lambda (x) (gimp-drawable-set-visible x FALSE)) visibles)
(map (lambda (x) (gimp-drawable-set-visible x FALSE)) cal-days)
(set! frame-layer (car (gimp-image-merge-visible-layers image EXPAND-AS-NECESSARY)))
(gimp-drawable-set-visible frame-layer FALSE)
(map (lambda (x) (gimp-drawable-set-visible x TRUE)) cal-days)
(set! dates-layer (car (gimp-image-merge-visible-layers image EXPAND-AS-NECESSARY)))
(gimp-layer-resize dates-layer
(car (gimp-drawable-width frame-layer))
(car (gimp-drawable-height frame-layer))
(- (car (gimp-drawable-offsets dates-layer)) (car (gimp-drawable-offsets frame-layer)))
(- (cadr (gimp-drawable-offsets dates-layer)) (cadr (gimp-drawable-offsets frame-layer))))
(map (lambda (x) (gimp-drawable-set-visible x TRUE)) visibles)
(gimp-drawable-set-visible frame-layer TRUE)
(gimp-drawable-set-name dates-layer (string-append (vector-ref months month) ", " (number->string year)))
(gimp-drawable-set-name frame-layer (vector-ref months month))
(gimp-context-set-background orig-bg)
(gimp-progress-update 1)
(gimp-displays-flush)
(gimp-context-pop)
(gimp-selection-load orig-sel)
(gimp-image-remove-channel image orig-sel)
(gimp-image-remove-layer image bg-layer)
(gimp-image-set-active-layer image drawable)
(gimp-image-undo-group-end image)
(list dates-layer frame-layer)
)
)
(define (script-fu-sg-calendar-year orig-image orig-drawable
lang
year
start-month
end-month
num-cols
padding
sunday? letters-in-day layout text-font number-font fontsize% justify? border border-color gravity)
(define (algebraic-prog start end elements)
(let ((elements (inexact->exact elements))
(incr (if (zero? start)
(/ end (- elements 1))
(/ (- (/ end start) 1) (- elements 1)) ) ) )
(let
loop ((cnt (- elements 1))
(lis (if (zero? start)
'(0)
'(1) ) ) )
(if (zero? cnt)
(if (zero? start)
(reverse lis)
(map * (reverse lis) (make-list elements start)) )
(loop (- cnt 1) (cons (+ (car lis) incr) lis)) ) ) ) )
; adjust input parameter so january is now first month
; Remember: december was first in the SF-OPTION list so that
; the default setting would be Jan to Dec
(set! end-month (modulo (pred end-month) 12))
(let* ((image 0)
(orig-x (car (gimp-drawable-offsets orig-drawable)))
(orig-y (cadr (gimp-drawable-offsets orig-drawable)))
(orig-sel 0)
(bounds (gimp-drawable-mask-intersect orig-drawable))
(buffer "")
(layer 0)
(display 0) )
(gimp-image-undo-group-start orig-image)
(set! orig-sel (car (gimp-selection-save orig-image)))
(unless (= (car (gimp-selection-is-empty orig-image)) TRUE)
(set! bounds (cdr bounds))
(set! orig-x (+ orig-x (car bounds)))
(set! orig-y (+ orig-y (cadr bounds)))
(gimp-rect-select orig-image orig-x orig-y (caddr bounds) (cadddr bounds) CHANNEL-OP-REPLACE FALSE 0) )
(set! buffer (car (gimp-edit-named-copy orig-drawable "buffer")))
(set! image (car (gimp-edit-named-paste-as-new buffer)))
(gimp-image-undo-disable image)
(set! display (car (gimp-display-new image)))
(set! layer (car (gimp-image-get-active-layer image)))
(gimp-buffer-delete buffer)
(let* ((num-months (succ (modulo (- end-month start-month) 12)))
(num-cols (min (truncate num-cols) num-months))
(width (car (gimp-drawable-width layer)))
(height (car (gimp-drawable-height layer)))
(x 0)
(y 0)
(w (floor (/ width num-cols)))
(num-rows (ceiling (/ num-months num-cols)))
(h (floor (/ height num-rows)))
(w-sel (/ (- width (* width padding 0.01)) num-cols))
(h-sel w-sel) ; assume square month initially
(x-offsets '())
(y-offsets '())
(temp-layer 0)
(month-index 0)
(month-fontsize 6)
(extents '()) )
(when (< h (+ h-sel (* h-sel padding 0.01))) ; shrink month height to make room for banner
(set! h-sel (- h (* h padding 0.009))) ; increase vertical padding a bit
(set! w-sel h-sel) ; re-calculate horizontal layout
)
(set! month-fontsize (apply min (map (lambda (text)
(sg-calendar-calc-fontsize text text-font 100 w-sel (- h h-sel)) )
(car (list-ref sg-calendar-translations lang)) )))
(set! y (+ (cadr (gimp-text-get-extents-fontname (caar (list-ref sg-calendar-translations lang))
month-fontsize
PIXELS
text-font ))
2) )
(set! y-offsets (if (> num-rows 1)
(map truncate (algebraic-prog y (- height h-sel) num-rows))
(list y) ))
(while (pair? y-offsets)
(set! x-offsets (if (> num-cols 1)
(map truncate (algebraic-prog 0 (- width w-sel) num-cols))
(list (/ (- width w-sel) 2)) ))
(while (and (pair? x-offsets) (< month-index num-months))
(set! x (car x-offsets))
(set! y (car y-offsets))
(gimp-rect-select image x y w-sel h-sel CHANNEL-OP-REPLACE FALSE 0)
(set! buffer (car (gimp-edit-named-copy layer "buffer")))
(gimp-floating-sel-to-layer (car (gimp-edit-named-paste layer buffer FALSE)))
(set! temp-layer (car (gimp-image-get-active-layer image)))
(gimp-buffer-delete buffer)
(let ((month (modulo (+ start-month month-index) 12)))
(script-fu-sg-calendar image temp-layer lang month year sunday?
letters-in-day layout text-font number-font
fontsize% justify? border border-color gravity)
(gimp-image-remove-layer image temp-layer)
(set! extents (gimp-text-get-extents-fontname (list-ref (car (list-ref sg-calendar-translations lang)) month)
month-fontsize
PIXELS
text-font ))
(set! temp-layer (car (gimp-text-fontname image -1
(+ x (/ (- w-sel (car extents)) 2))
(- y (cadr extents) (/ (cadddr extents) -2))
(list-ref (car (list-ref sg-calendar-translations lang)) month)
0 TRUE
month-fontsize PIXELS text-font ))))
(set! x-offsets (cdr x-offsets))
(set! month-index (succ month-index)) )
(set! y-offsets (cdr y-offsets)) ) )
;; Now, transfer the rendered layers to original image
(gimp-selection-none image)
(let loop ((layers (cdr (reverse (vector->list (cadr (gimp-image-get-layers image))))))
(target-layer orig-drawable) )
(if (null? layers)
#t
(begin
(let ((x (car (gimp-drawable-offsets (car layers))))
(y (cadr (gimp-drawable-offsets (car layers))))
(pos (car (gimp-image-get-layer-position orig-image target-layer))) )
(set! target-layer (car (gimp-layer-new-from-drawable (car layers) orig-image)))
(gimp-image-add-layer orig-image target-layer pos)
(gimp-layer-set-offsets target-layer (+ orig-x x) (+ orig-y y)) )
(loop (cdr layers) target-layer) ) ) )
(gimp-selection-load orig-sel)
(gimp-image-remove-channel orig-image orig-sel)
(gimp-image-set-active-layer orig-image orig-drawable)
(gimp-image-undo-group-end orig-image)
(gimp-display-delete display)
(gimp-displays-flush)
)
)
(script-fu-register "script-fu-sg-calendar"
"Calendar..."
"Generate a calendar overlay for current layer"
"Saul Goode"
"Saul Goode"
"10/26/09, updated Jan 2012"
"RGB*,GRAY*"
SF-IMAGE "Image" 0
SF-DRAWABLE "Drawable" 0
SF-OPTION "Language" sg-calendar-languages
SF-OPTION "Month" (caar sg-calendar-translations)
SF-ADJUSTMENT "Year" '( 2013 1753 2050 1 10 0 1 )
SF-TOGGLE "Sunday first" TRUE
SF-OPTION "Day format" '("S M T ..." "Su Mo Tu ..." "Sun Mon Tue ...")
SF-OPTION "Layout" '( "Allow 6-week span" "Force 6-week span" "Wrap Week 6 to Week 1" "Wrap Week 6 to Week 5")
SF-FONT "Text font" "Sans"
SF-FONT "Number font" "Sans"
SF-ADJUSTMENT "Font Size (% of maximum)" '( 100 0 100 1 10 0 1)
SF-TOGGLE "Right Justify" TRUE
SF-ADJUSTMENT "Border width" '( 1 0 5 1 1 0 1 )
SF-COLOR "Border color" '(0 0 0)
SF-OPTION "Date Position" '( "top-left" "top-center" "top-right" "left-center" "center" "right-center" "bottom-left" "bottom-center" "bottom-right")
)
(script-fu-menu-register "script-fu-sg-calendar"
"<Image>/Filters/Render"
)
(script-fu-register "script-fu-sg-calendar-year"
"Calendar year..."
"Generate a calendar for current layer"
"Saul Goode"
"Saul Goode"
"Dec 2010, updated Jan 2012"
"RGB*,GRAY*"
SF-IMAGE "Image" 0
SF-DRAWABLE "Drawable" 0
SF-OPTION "Language" sg-calendar-languages
SF-ADJUSTMENT "Year" '( 2015 1753 2050 1 10 0 1 )
SF-OPTION "Start Month" (caar sg-calendar-translations)
SF-OPTION "End Month" (cons (car (last (caar sg-calendar-translations)))
(butlast (caar sg-calendar-translations)))
SF-ADJUSTMENT "Columns" '( 4 1 12 1 10 0 1 )
SF-ADJUSTMENT "Padding" '( 10 0 80 1 10 0 1 )
SF-TOGGLE "Sunday first" TRUE
SF-OPTION "Day format" '("S M T ..." "Su Mo Tu ..." "Sun Mon Tue ...")
SF-OPTION "Layout" '( "Allow 6-week span" "Force 6-week span" "Wrap Week 6 to Week 1" "Wrap Week 6 to Week 5")
SF-FONT "Text font" "Sans"
SF-FONT "Number font" "Sans"
SF-ADJUSTMENT "Font Size (% of maximum)" '( 100 0 100 1 10 0 1)
SF-TOGGLE "Right Justify" TRUE
SF-ADJUSTMENT "Border width" '( 1 0 5 1 1 0 1 )
SF-COLOR "Border color" '(0 0 0)
SF-OPTION "Date Position" '( "top-left" "top-center" "top-right" "left-center" "center" "right-center" "bottom-left" "bottom-center" "bottom-right")
)
(script-fu-menu-register "script-fu-sg-calendar-year"
"<Image>/Filters/Render"
)