%!PS-ADOBE-3.0
% $Id: pscdcover.ps,v 1.26 2004/03/09 15:06:11 cbouvi Exp $
%
%  Copyright (C) 2004 Cédric Bouvier
%
%  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.
%
%  You should have received a copy of the GNU General Public License along with
%  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
%  Place, Suite 330, Boston, MA  02111-1307  USA
%
% $Log: pscdcover.ps,v $
% Revision 1.26  2004/03/09 15:06:11  cbouvi
% Uses ISO-8859-15 encoding instead of ISO-8859-1
%
% Revision 1.25  2004/02/25 15:12:35  cbouvi
% Bugfix: empty title caused a division by zero
%
% Revision 1.24  2004/02/24 14:58:04  cbouvi
% Long titles are now scaled down to fit in the page width
%
% Revision 1.23  2004/02/24 14:35:35  cbouvi
% Added --cd-color and --folder-color to override icons default colors
%
% Revision 1.22  2004/02/24 13:51:30  cbouvi
% Added support for --color
%
% Revision 1.21  2004/02/05 10:25:28  cbouvi
% Fixed clipping on side labels (upside down title would overprint the icon)
%
% Revision 1.20  2004/02/05 10:15:50  cbouvi
% Updated comments
%
% Revision 1.19  2004/02/04 16:55:11  cbouvi
% Code cleanup
%
% Revision 1.18  2004/02/04 16:22:16  cbouvi
% Prints one of the side label topsy-turvy. Code cleanup
%
% Revision 1.17  2004/02/04 12:44:09  cbouvi
% Added switch --separator to add a column separator line
%
% Revision 1.16  2004/02/02 12:56:55  cbouvi
% Added --minwidth to eliminate too narrow columns
%
% Revision 1.15  2004/02/02 12:23:53  cbouvi
% Added switch --all to force printing even empty pages
%
% Revision 1.14  2004/02/02 10:10:07  cbouvi
% --columns=0 means automatic column width
%
% Revision 1.13  2004/01/30 14:09:14  cbouvi
% Code cleanup
%
% Revision 1.12  2004/01/30 13:51:05  cbouvi
% Let clip of column extend to the right margin
%
% Revision 1.11  2004/01/30 09:47:43  cbouvi
% Added --columns option
%
% Revision 1.10  2004/01/29 14:20:38  cbouvi
% Added LICENSE
%
% Revision 1.9  2004/01/28 16:09:19  cbouvi
% Reduced indenting of regular files
%
% Revision 1.8  2004/01/28 15:59:30  cbouvi
% Reduced line spacing
%
% Revision 1.7  2004/01/28 15:10:08  cbouvi
% Fixed a bug (second column was trespassing on title)
%
% Revision 1.6  2004/01/28 14:40:50  cbouvi
% Added support for optional bounding boxes
%
% Revision 1.4  2004/01/28 14:34:03  cbouvi
% Added variables to control layout
%
% Revision 1.3  2004/01/28 14:04:46  cbouvi
% Added function to draw a rectangle
%
% Revision 1.2  2004/01/28 13:56:48  cbouvi
% Added comments. Started implementing overflow on the back cover
%
%
%%BeginSetup
%
%%BeginFeature: *PageSize A4
<</PageSize [595 842] /ImagingBBox null>> setpagedevice
%%EndFeature
%%EndSetup

% Copy standard ISO-8859-1 (Latin1) encoding to not-so-standard ISO-8859-15
% (Latin9) encoding. Only Latin1 is included in standard PostScript
/ISOLatin9Encoding ISOLatin1Encoding length array def
ISOLatin1Encoding ISOLatin9Encoding copy pop

% Change the 8 characters that differ between Latin9 and Latin1
<<
    164   /Euro     166   /Scaron   168   /scaron   180   /Zcaron
    184   /zcaron   188   /OE       189   /oe       190   /Ydieresis
>> { ISOLatin9Encoding 3 1 roll put } forall

/F0
/Helvetica findfont dup length dict begin
    {
        1 index /FID ne {def} {pop pop} ifelse
    } forall
    % Use our newly defined ISO-8859-15 (Latin9) encoding and enjoy euro signs,
    % "E dans l'O" and the like.
    /Encoding ISOLatin9Encoding def
    currentdict
end
definefont pop
/F0 findfont 10 scalefont setfont

% all dimensions will be given in millimeters
/mm { 25.4 div 72 mul } def

% The page dimensions: this is valid for both the front sleeve and inner
% sleeve. Both will actually be printed side by side on the first output A4.
/page_height  120 mm def
/page_width   120 mm def

% The margins, or padding around each column. margin_top will be applied below
% the CD title on the front page, and below the cover edge on the other pages.
/margin_top     2 mm def
/margin_left    1 mm def
/margin_right   1 mm def

% These parameters will s///ubstitued by the wrapper Perl program.
/number_of_columns #COLUMNS# def
/min_width         #MIN_WIDTH# mm def
/separator         #SEPARATOR# def
/force_all_pages   #FORCE_ALL_PAGES# def
/cd_title_string   (#CD_TITLE#) def
/color             #COLOR# def
/cd_color          { #CD_COLOR# } def
/folder_color      { #FOLDER_COLOR# } def

%
% Some helper functions
%

% the y coordinate of the bottom of the page. Since origin is top left, this is
% a negative number.
/page_bottom { page_height neg } def

% the width of the current column, either a simple division if the number of
% columns is fixed, or calculated based on the widest filename if it is
% automatic.
/column_width {
    number_of_columns 0 eq {
        right_most margin_right corner_x sub add
    }
    {
        page_width number_of_columns div
    } ifelse
} def

% counters
/current_column 1 def  % current_column will reset to 1 at each new page.
/current_page 1 def

% rect_box
% Creates a rectangular path
/rect_box { % stack x y w h
    newpath
    /box_height exch def
    /box_width exch def
    moveto
    0 box_height rlineto
    box_width 0 rlineto
    0 box_height neg rlineto
    closepath
} def

% draw_page_frame
% Draws a dim gray frame around the page.
/draw_page_frame {
    % #START_BOX# % will be skipped when wrapper program called with --nobox
    gsave
        .3 setlinewidth
        .8 setgray
        0 0 page_width page_bottom rect_box
        stroke
    grestore
    % #STOP_BOX#
} def

% choose_color
% calls setgray or setrgbcolor with the arguments, depending on the value of
% /color
/choose_color { % stack: gray r g b
    color 0 eq {
        pop pop pop
        setgray
    }
    {
        setrgbcolor
        pop
    }
    ifelse
} def

% draw_cd
% Draws a CD icon.
/draw_cd { % stack: x y size
    % (x,y) is the bottom left corner of the icon.
    3 1 roll % stack: size x y
    gsave
        translate

        % the drawing is done for a diameter of 12 mm. Let's scale to whatever
        % size is asked for:
        12 mm div dup scale

        6 mm 6 mm translate % move to the center
        1 setlinewidth
        newpath
        0 0 6 mm 0 360 arc  % outer circle
        2 mm 0 moveto
        0 0 2 mm 0 360 arc  % inner circle of the aluminum part
        gsave
            .8     % gray
            cd_color % light yellow
            choose_color
            eofill          % aluminium filling
        grestore
        stroke
        newpath
        0 0 .75 mm 0 360 arc % hole in the center
        stroke
    grestore
} def

% draw_folder
% Draws a Folder icon
/draw_folder { % stack: x y size
    3 1 roll
    gsave
        translate

        % the drawing is done for a 12×12mm icon. Let's scale
        12 mm div dup scale
        1 setlinewidth

        2.4 mm 2.2 mm translate

        % far side rectangle, with thumb tab
        newpath
        0 0 moveto
        0 7 mm rlineto
        .8 mm 1.6 mm rlineto
        3 mm 0 rlineto
        .8 mm -1.6 mm rlineto
        5 mm 0 rlineto
        0 -7 mm rlineto
        closepath
        gsave
            .7        % gray
            folder_color % light blue
            choose_color
            fill
        grestore
        stroke

        % front rectangle, 20° open
        newpath
        0 0 moveto
        20 rotate
        0 7 mm rlineto
        -20 rotate
        9.6 mm 0 rlineto
        20 rotate
        0 -7 mm rlineto
        -20 rotate
        closepath
        gsave
            .7        % gray
            folder_color % light blue
            choose_color
            fill
        grestore
        stroke
    grestore
} def

/force_fit { % stack: string max_width
    exch stringwidth pop dup 0 eq {
        pop pop
    }
    {
        div dup 1 lt {
            1 scale
        }
        {
            pop
        }
        ifelse
    }
    ifelse
} def

% cd_title
% Writes the CD title (with icon) and horizontal ruler.
% The title is clipped to a 120×8 mm box.
/cd_title { % stack: string x y (abs coord. of top-left corner)
    gsave

        % horizontal ruler
        newpath
        1 mm -8 mm moveto
        119 mm -8 mm lineto
        1 setlinewidth
        stroke

        % clip
        newpath
        moveto
        120 mm 0 rlineto
        0 -8 mm rlineto
        -120 mm 0 rlineto
        closepath
        clip

        % icon
        1 mm -7 mm 6 mm draw_cd

        % text
        /F0 findfont 14 scalefont setfont
        8 mm -6 mm moveto
        dup 110 mm force_fit
        show

    grestore
} def

% first page
/first_page {

    % this centers the CD cover on an A4
    45 mm 28.5 mm translate

    % switch to landscape
    90 rotate

    draw_page_frame
    cd_title_string 0 0 cd_title

} def

% second_page
/second_page {

    % move to the second page
    page_width 0 translate
    draw_page_frame

    /corner_x 0 def
    /corner_y 0 def
} def

/back_page {

    % This centers the back cover on the first half of an A4. This allows to
    % print two back covers on one sheet, by simply feeding the same sheet
    % upside down into the printer.
    30 mm 276 mm translate
    /page_height 117 mm def
    /page_width  138 mm def
    /corner_x 0 def

    % a function to print the side label, with icon and CD title
    % Last parameter should be 1 to print the title upside down
    /side_label {
        /upside_down exch def
        gsave
            translate
            -90 rotate % titles are printed vertically
            0 0 page_height 6 mm rect_box
            % #START_BOX# % will be skipped when wrapper program called with --nobox
            gsave
                .8 setgray
                .3 setlinewidth
                stroke
            grestore
            % #STOP_BOX#
            
            /F0 findfont 11 scalefont setfont

            % draw the little icon
            1 mm 1 mm 4 mm draw_cd

            6 mm 0 page_height 8 mm sub 6 mm rect_box clip

            % Prints the title
            6 mm 1.5 mm
            upside_down 0 eq {
                % straight
                moveto
                cd_title_string dup page_height 8 mm sub force_fit
                show
            }{
                % upside down
                gsave
                    translate
                    % first go to where the string would end, reverse and print
                    cd_title_string stringwidth pop dup page_height 8 mm sub gt {
                        pop page_height 8 mm sub
                    } if
                    8.5 moveto
                    180 rotate
                    cd_title_string dup page_height 8 mm sub force_fit
                    show
                grestore

            } ifelse
        grestore
    } def

    % one side label on the left, upside down
    0 0 1 side_label
    % one side label on the right, straight
    6 mm page_width add 0 0 side_label

    6 mm 0 translate
    draw_page_frame
    /corner_x 0 def
    /corner_y 0 def
    gsave
} def

/next_page {

    /current_page current_page 1 add def
    /current_column 1 def
    current_page 2 eq {
        second_page
    } if
    current_page 3 eq {
        grestore
        showpage
        back_page
    } if

} def

% start_new_column
% Creates a new clipping region. The rectangle will go down to the bottom of
% the page, i.e., 120mm, regardless of the starting position.
/start_new_column { % x y (abs coord. of top left corner)

    % save the top-left corner so that we know where to start next column.
    gsave
    /corner_y exch def
    /corner_x exch def

    % draw a separator line if option is set and not on the first column.
    separator 0 ne current_column 1 ne and {
        newpath
        corner_x corner_y moveto
        corner_x page_bottom lineto
        .3 setlinewidth
        stroke
    } if
    % clipping
    newpath
    corner_x corner_y moveto

    number_of_columns 0 ne {
        % if column width is fixed, clip at the exact column width, so that
        % long file names are truncated and do not trespass on the next column.
        column_width 0 rlineto
        currentpoint pop page_bottom lineto
    }{
        % if column width is automatic (number_of_columns == 0), clip at the
        % very right of the page: the next column will start right after the
        % longest filename).
        page_width corner_y lineto
        page_width page_bottom lineto
    } ifelse
    corner_x page_bottom lineto
    closepath
    clip
} def

% next_column
% Starts another column, possibly on next page.
/next_column {

    grestore
    /corner_x corner_x column_width add def
    /current_column current_column 1 add def

    % go to next page if the room left on the right is lower than the minimum
    % allowed.
    corner_x page_width min_width sub ge { next_page } if

    corner_x corner_y start_new_column
    corner_x margin_left add corner_y margin_top sub moveto
    /right_most currentpoint pop def
} def

% check_column
% Test whether bottom of current column is reached and jumps to the next one.
/check_column { % stack: x y (rel coord.)

    /delta_y exch def
    /delta_x exch def
    delta_x delta_y rmoveto % move attempt
    currentpoint exch pop page_bottom lt { % test against bottom
        next_column
        delta_x delta_y rmoveto % move again from top of next column
    } if
} def

% update_right_most
% Update the right_most variable to the current x coordinate if it is greater
% than the current right_most value. This is only useful for automatic column
% width.
/update_right_most {
    currentpoint pop right_most gt {
        /right_most currentpoint pop def
    } if
} def

% folder_title
% Displays a folder with its icon at a given indent
/folder_title { % stack: text indent
    % indent==0 means left most.
    0 -10 check_column
    gsave
        4 mm mul currentpoint pop add dup currentpoint exch pop 10 draw_folder
        5 mm add currentpoint exch pop 1 mm add moveto
        /F0 findfont 8 scalefont setfont
        show
        update_right_most
    grestore
} def

% file_title
% Displays a filename at a given indent
/file_title { % stack: text indent
    % indent==0 means left most.
    0 -8 check_column
    gsave
        1 sub 4 mm mul currentpoint pop add 5 mm add currentpoint exch pop 1 mm add moveto
        /F0 findfont 6 scalefont setfont
        show
        update_right_most
    grestore
} def

gsave
first_page
0 -8 mm start_new_column
margin_left -10 mm moveto
/right_most currentpoint pop def

% The section below can be edited at will: the actual layout will be calculated
% by the program above. One can add or remove lines without worrying about the
% way they will be dispatched across pages and columns.
%
% Directory or file names are between (parentheses). Should one wish to include
% parentheses within a directory or file name, they must be escape by preceding
% them with a backslash: \( and \).
% The number that follows the parentheses is the depth within the directory
% tree, 0 being at the root.
% folder_title draws a folder icon, while file_title draws nothing and uses a
% smaller font size.
%
% #START_CONTENT#
(Folder 1) 0 folder_title
(Folder 1.1) 1 folder_title
(file 1.1.1) 1 file_title
(file 1.1.2) 1 file_title
(file 1.1.3) 1 file_title
(Folder 1.2) 1 folder_title
(Folder 1.2.1) 2 folder_title
(Folder 2) 0 folder_title
% #STOP_CONTENT#

% draws the missing pages if the directory listing was too short and the option
% is set.
force_all_pages 1 eq {
    current_page 2 lt { grestore next_page gsave } if
    current_page 3 lt { grestore next_page } if
} if

grestore
showpage