rrtf 0.1.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.byebug_history +6 -3
- data/CHANGELOG.md +24 -0
- data/README.md +194 -84
- data/documentation/RRTF.html +5 -5
- data/documentation/RRTF/AnonymousStyle.html +792 -0
- data/documentation/RRTF/BorderFormatting.html +821 -0
- data/documentation/RRTF/BorderStyle.html +493 -0
- data/documentation/RRTF/CharacterFormatting.html +293 -162
- data/documentation/RRTF/CharacterStyle.html +53 -109
- data/documentation/RRTF/Colour.html +61 -1
- data/documentation/RRTF/ColourTable.html +52 -52
- data/documentation/RRTF/CommandNode.html +367 -971
- data/documentation/RRTF/ContainerNode.html +44 -44
- data/documentation/RRTF/Converters.html +1 -1
- data/documentation/RRTF/Converters/HTML.html +1 -1
- data/documentation/RRTF/Converters/HTML/Helpers.html +1 -1
- data/documentation/RRTF/Converters/HTML/Node.html +1 -1
- data/documentation/RRTF/Converters/HTML/NodeSet.html +1 -1
- data/documentation/RRTF/Document.html +267 -255
- data/documentation/RRTF/DocumentFormatting.html +833 -0
- data/documentation/RRTF/DocumentProperties.html +444 -0
- data/documentation/RRTF/Font.html +1 -1
- data/documentation/RRTF/FontTable.html +1 -1
- data/documentation/RRTF/FooterNode.html +16 -16
- data/documentation/RRTF/GeometryNode.html +774 -0
- data/documentation/RRTF/GeometryProperties.html +1014 -0
- data/documentation/RRTF/HeaderNode.html +16 -16
- data/documentation/RRTF/ImageNode.html +705 -492
- data/documentation/RRTF/Information.html +1 -1
- data/documentation/RRTF/LinkNode.html +10 -10
- data/documentation/RRTF/ListLevel.html +1 -1
- data/documentation/RRTF/ListLevelNode.html +37 -37
- data/documentation/RRTF/ListMarker.html +1 -1
- data/documentation/RRTF/ListNode.html +19 -19
- data/documentation/RRTF/ListTable.html +1 -1
- data/documentation/RRTF/ListTemplate.html +1 -1
- data/documentation/RRTF/ListTextNode.html +14 -14
- data/documentation/RRTF/Node.html +26 -26
- data/documentation/RRTF/Page.html +129 -0
- data/documentation/RRTF/Page/Margin.html +1158 -0
- data/documentation/RRTF/Page/Size.html +946 -0
- data/documentation/RRTF/PageFormatting.html +954 -0
- data/documentation/RRTF/ParagraphFormatting.html +338 -56
- data/documentation/RRTF/ParagraphNode.html +10 -10
- data/documentation/RRTF/ParagraphStyle.html +72 -111
- data/documentation/RRTF/PositionFormatting.html +780 -0
- data/documentation/RRTF/PositionStyle.html +424 -0
- data/documentation/RRTF/Properties.html +243 -0
- data/documentation/RRTF/RTFError.html +21 -10
- data/documentation/RRTF/ShadingFormatting.html +712 -0
- data/documentation/RRTF/ShadingStyle.html +424 -0
- data/documentation/RRTF/Style.html +284 -697
- data/documentation/RRTF/Stylesheet.html +36 -3
- data/documentation/RRTF/TableCellNode.html +131 -131
- data/documentation/RRTF/TableNode.html +82 -82
- data/documentation/RRTF/TableRowNode.html +53 -53
- data/documentation/RRTF/TextNode.html +46 -46
- data/documentation/RRTF/Utilities.html +837 -17
- data/documentation/_index.html +139 -6
- data/documentation/class_list.html +1 -1
- data/documentation/file.README.html +218 -87
- data/documentation/index.html +218 -87
- data/documentation/method_list.html +631 -391
- data/documentation/top-level-namespace.html +1 -1
- data/examples/01.rtf +947 -20
- data/examples/01_everything.rb +176 -0
- data/examples/02.rtf +13 -0
- data/examples/02_basic_paragraph.rb +10 -0
- data/examples/03.rtf +20 -0
- data/examples/03_paragraph_inline_style.rb +14 -0
- data/examples/04.rtf +21 -0
- data/examples/04_paragraph_with_character_style.rb +18 -0
- data/examples/05.rtf +21 -0
- data/examples/05_hyperlinks.rb +21 -0
- data/examples/06.rtf +21 -0
- data/examples/06_basic_list.rb +21 -0
- data/examples/07.rtf +28 -0
- data/examples/07_nested_list.rb +27 -0
- data/examples/08.rtf +807 -0
- data/examples/08_images.rb +17 -0
- data/examples/09.rtf +84 -0
- data/examples/09_shapes.rb +56 -0
- data/examples/10.rtf +34 -0
- data/examples/10_stylesheet.rb +18 -0
- data/examples/resources/images/redshirt.png +0 -0
- data/examples/resources/images/redshirts.jpg +0 -0
- data/examples/resources/json/redshirt_styles.json +72 -8
- data/examples/~$01.rtf +0 -0
- data/lib/rrtf.rb +4 -16
- data/lib/rrtf/colour.rb +8 -0
- data/lib/rrtf/formatting.rb +988 -0
- data/lib/rrtf/node.rb +17 -1851
- data/lib/rrtf/node/command_node.rb +242 -0
- data/lib/rrtf/node/container_node.rb +75 -0
- data/lib/rrtf/node/document.rb +339 -0
- data/lib/rrtf/node/footer_node.rb +47 -0
- data/lib/rrtf/node/geometry_node.rb +65 -0
- data/lib/rrtf/node/header_node.rb +47 -0
- data/lib/rrtf/node/image_node.rb +175 -0
- data/lib/rrtf/node/link_node.rb +10 -0
- data/lib/rrtf/node/list_level_node.rb +44 -0
- data/lib/rrtf/node/list_node.rb +30 -0
- data/lib/rrtf/node/list_text_node.rb +22 -0
- data/lib/rrtf/node/node.rb +53 -0
- data/lib/rrtf/node/paragraph_node.rb +11 -0
- data/lib/rrtf/node/table_cell_node.rb +233 -0
- data/lib/rrtf/node/table_node.rb +136 -0
- data/lib/rrtf/node/table_row_node.rb +92 -0
- data/lib/rrtf/node/text_node.rb +76 -0
- data/lib/rrtf/page.rb +7 -0
- data/lib/rrtf/page/margin.rb +98 -0
- data/lib/rrtf/page/size.rb +98 -0
- data/lib/rrtf/properties.rb +3 -0
- data/lib/rrtf/properties/document_properties.rb +34 -0
- data/lib/rrtf/properties/geometry_properties.rb +380 -0
- data/lib/rrtf/properties/properties.rb +13 -0
- data/lib/rrtf/style.rb +4 -5
- data/lib/rrtf/style/anonymous_style.rb +73 -0
- data/lib/rrtf/style/border_style.rb +27 -0
- data/lib/rrtf/style/character_style.rb +1 -7
- data/lib/rrtf/style/paragraph_style.rb +0 -6
- data/lib/rrtf/style/position_style.rb +26 -0
- data/lib/rrtf/style/shading_style.rb +26 -0
- data/lib/rrtf/style/style.rb +60 -101
- data/lib/rrtf/utilities.rb +138 -0
- data/lib/rrtf/version.rb +1 -1
- data/rrtf.gemspec +1 -0
- metadata +85 -10
- data/examples/01_mac_libreoffice5_2_3_3.png +0 -0
- data/examples/01_mac_pages6_2.png +0 -0
- data/examples/01_mac_textedit1_12.png +0 -0
- data/examples/01_mac_word15_36.png +0 -0
- data/examples/01_styles_and_paragraphs.rb +0 -32
- data/lib/rrtf/paper.rb +0 -53
- data/lib/rrtf/style/document_style.rb +0 -116
- data/lib/rrtf/style/formatting.rb +0 -320
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'rrtf'
|
|
2
|
+
|
|
3
|
+
DIR = File.dirname(__FILE__)
|
|
4
|
+
|
|
5
|
+
rtf = RRTF::Document.new
|
|
6
|
+
rtf.image(DIR+'/resources/images/redshirt.png',
|
|
7
|
+
"width" => "2in", # can also set "height"
|
|
8
|
+
"sizing_mode" => "FIX_ASPECT_RATIO", # can also be "ABSOLUTE"
|
|
9
|
+
"border" => {
|
|
10
|
+
"sides" => "ALL",
|
|
11
|
+
"color" => '#ff0000',
|
|
12
|
+
"line_type" => "DOT",
|
|
13
|
+
"width" => "5pt",
|
|
14
|
+
"spacing" => "12pt"
|
|
15
|
+
}
|
|
16
|
+
)
|
|
17
|
+
File.open(DIR+'/08.rtf', 'w') { |file| file.write(rtf.to_rtf) }
|
data/examples/09.rtf
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{\rtf1\ansi\deff0\deflang1033\plain\fs24\fet1
|
|
2
|
+
{\fonttbl
|
|
3
|
+
{\f0\fswiss Helvetica;}
|
|
4
|
+
}
|
|
5
|
+
{\colortbl
|
|
6
|
+
;
|
|
7
|
+
\red255\green255\blue255;
|
|
8
|
+
}
|
|
9
|
+
{\info
|
|
10
|
+
{\createim\yr2017\mo7\dy31\hr20\min2}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
\hyphauto1\paperw12247\paperh15819\margl1440\margr1440\margt1440\margb1440
|
|
14
|
+
{\shp{\*\shpinst\shpleft0\shpright2880\shptop0\shpbottom2880\shpbxpage\shpbxignore\shpbypage\shpbyignore
|
|
15
|
+
{\sp{\sn shapeType}{\sv 1}}
|
|
16
|
+
{\sp{\sn posh}{\sv 0}}
|
|
17
|
+
{\sp{\sn posrelh}{\sv 1}}
|
|
18
|
+
{\sp{\sn posv}{\sv 0}}
|
|
19
|
+
{\sp{\sn posrelv}{\sv 1}}
|
|
20
|
+
{\sp{\sn sizerelh}{\sv 0}}
|
|
21
|
+
{\sp{\sn sizerelv}{\sv 0}}
|
|
22
|
+
{\sp{\sn fFilled}{\sv 1}}
|
|
23
|
+
{\sp{\sn fillColor}{\sv 13421772}}
|
|
24
|
+
{\sp{\sn fLine}{\sv 0}}
|
|
25
|
+
{\sp{\sn geoLeft}{\sv 0}}
|
|
26
|
+
{\sp{\sn geoTop}{\sv 0}}
|
|
27
|
+
{\sp{\sn geoRight}{\sv 30000}}
|
|
28
|
+
{\sp{\sn geoBottom}{\sv 30000}}
|
|
29
|
+
{\sp{\sn fLineOK}{\sv 1}}
|
|
30
|
+
{\sp{\sn fFillOK}{\sv 1}}
|
|
31
|
+
{\sp{\sn f3DOK}{\sv 1}}
|
|
32
|
+
}}
|
|
33
|
+
{\shp{\*\shpinst\shpleft3600\shpright7920\shptop7200\shpbottom11520\shpbxpage\shpbxignore\shpbypage\shpbyignore
|
|
34
|
+
{\sp{\sn shapeType}{\sv 202}}
|
|
35
|
+
{\sp{\sn posh}{\sv 0}}
|
|
36
|
+
{\sp{\sn posrelh}{\sv 1}}
|
|
37
|
+
{\sp{\sn posv}{\sv 0}}
|
|
38
|
+
{\sp{\sn posrelv}{\sv 1}}
|
|
39
|
+
{\sp{\sn sizerelh}{\sv 0}}
|
|
40
|
+
{\sp{\sn sizerelv}{\sv 0}}
|
|
41
|
+
{\sp{\sn fFilled}{\sv 1}}
|
|
42
|
+
{\sp{\sn fillColor}{\sv 255}}
|
|
43
|
+
{\sp{\sn fLine}{\sv 1}}
|
|
44
|
+
{\sp{\sn lineColor}{\sv 0}}
|
|
45
|
+
{\sp{\sn lineWidth}{\sv 38100}}
|
|
46
|
+
{\sp{\sn geoLeft}{\sv 0}}
|
|
47
|
+
{\sp{\sn geoTop}{\sv 0}}
|
|
48
|
+
{\sp{\sn geoRight}{\sv 30000}}
|
|
49
|
+
{\sp{\sn geoBottom}{\sv 30000}}
|
|
50
|
+
{\sp{\sn fLineOK}{\sv 1}}
|
|
51
|
+
{\sp{\sn fFillOK}{\sv 1}}
|
|
52
|
+
{\sp{\sn f3DOK}{\sv 1}}
|
|
53
|
+
{\shptxt
|
|
54
|
+
{\pard\ql\ltrpar\cf1
|
|
55
|
+
Should you ever find yourself on a spacefaring vessel wearing a
|
|
56
|
+
{\b\i\ul
|
|
57
|
+
red
|
|
58
|
+
}
|
|
59
|
+
shirt, take heed and be on guard, for danger is immanent and you are likely expendable among the crew.
|
|
60
|
+
\par}}}}
|
|
61
|
+
{\shp{\*\shpinst\shpleft5760\shpright10080\shptop0\shpbottom4320\shpbxmargin\shpbxignore\shpbymargin\shpbyignore
|
|
62
|
+
{\sp{\sn shapeType}{\sv 0}}
|
|
63
|
+
{\sp{\sn posh}{\sv 0}}
|
|
64
|
+
{\sp{\sn posrelh}{\sv 0}}
|
|
65
|
+
{\sp{\sn posv}{\sv 0}}
|
|
66
|
+
{\sp{\sn posrelv}{\sv 0}}
|
|
67
|
+
{\sp{\sn sizerelh}{\sv 0}}
|
|
68
|
+
{\sp{\sn sizerelv}{\sv 0}}
|
|
69
|
+
{\sp{\sn fFilled}{\sv 1}}
|
|
70
|
+
{\sp{\sn fillColor}{\sv 52224}}
|
|
71
|
+
{\sp{\sn fLine}{\sv 1}}
|
|
72
|
+
{\sp{\sn lineColor}{\sv 10027008}}
|
|
73
|
+
{\sp{\sn geoLeft}{\sv 0}}
|
|
74
|
+
{\sp{\sn geoTop}{\sv 0}}
|
|
75
|
+
{\sp{\sn geoRight}{\sv 30000}}
|
|
76
|
+
{\sp{\sn geoBottom}{\sv 30000}}
|
|
77
|
+
{\sp{\sn pVerticies}{\sv 8;6;(0,0);(20000,0);(30000,0);(30000,15000);(30000,30000);(0,0)}}
|
|
78
|
+
{\sp{\sn pSegmentInfo}{\sv 2;6;16384;1;8193;1;24577;32768}}
|
|
79
|
+
{\sp{\sn pConnectionSites}{\sv 8;4;(0,0);(20000,0);(30000,30000);(0,0)}}
|
|
80
|
+
{\sp{\sn fLineOK}{\sv 1}}
|
|
81
|
+
{\sp{\sn fFillOK}{\sv 1}}
|
|
82
|
+
{\sp{\sn f3DOK}{\sv 1}}
|
|
83
|
+
}}
|
|
84
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
require 'rrtf'
|
|
2
|
+
|
|
3
|
+
DIR = File.dirname(__FILE__)
|
|
4
|
+
|
|
5
|
+
rtf = RRTF::Document.new
|
|
6
|
+
rtf.geometry(
|
|
7
|
+
"type" => "RECTANGLE",
|
|
8
|
+
"fill_color" => '#cccccc',
|
|
9
|
+
"top" => 0,
|
|
10
|
+
"left" => 0,
|
|
11
|
+
"width" => "2in",
|
|
12
|
+
"height" => "2in",
|
|
13
|
+
"horizontal_reference" => "PAGE",
|
|
14
|
+
"vertical_reference" => "PAGE"
|
|
15
|
+
)
|
|
16
|
+
rtf.geometry(
|
|
17
|
+
"type" => "TEXT_BOX",
|
|
18
|
+
"fill_color" => '#ff0000',
|
|
19
|
+
"line_color" => '#000000',
|
|
20
|
+
"line_width" => '3pt',
|
|
21
|
+
"top" => "5in",
|
|
22
|
+
"left" => "2.5in",
|
|
23
|
+
"width" => "3in",
|
|
24
|
+
"height" => "3in",
|
|
25
|
+
"horizontal_reference" => "PAGE",
|
|
26
|
+
"vertical_reference" => "PAGE"
|
|
27
|
+
) do |box|
|
|
28
|
+
box.paragraph("foreground_color" => '#ffffff') do |p|
|
|
29
|
+
p << "Should you ever find yourself on a spacefaring vessel wearing a "
|
|
30
|
+
p.apply(
|
|
31
|
+
"italic" => true,
|
|
32
|
+
"bold" => true,
|
|
33
|
+
"underline" => "SINGLE"
|
|
34
|
+
) << "red"
|
|
35
|
+
p << " shirt, take heed and be on guard, for danger "
|
|
36
|
+
p << "is immanent and you are likely expendable among the crew."
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
rtf.geometry(
|
|
40
|
+
"type" => "CUSTOM",
|
|
41
|
+
"path" => [
|
|
42
|
+
["START_AT", [0,0] ],
|
|
43
|
+
["LINE_TO", ['2in', 0] ],
|
|
44
|
+
["CUBIC_BEZIER_TO", ['3in', 0], ['3in', '1.5in'], ['3in', '3in'] ],
|
|
45
|
+
["LINE_TO", [0, 0] ],
|
|
46
|
+
["CLOSE_PATH" ],
|
|
47
|
+
["END" ]
|
|
48
|
+
],
|
|
49
|
+
"fill_color" => '#00cc00',
|
|
50
|
+
"line_color" => '#000099',
|
|
51
|
+
"top" => 0,
|
|
52
|
+
"left" => "4in",
|
|
53
|
+
"width" => "3in",
|
|
54
|
+
"height" => "3in"
|
|
55
|
+
)
|
|
56
|
+
File.open(DIR+'/09.rtf', 'w') { |file| file.write(rtf.to_rtf) }
|
data/examples/10.rtf
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{\rtf1\ansi\deff0\deflang1033\plain\fs24\fet1
|
|
2
|
+
{\fonttbl
|
|
3
|
+
{\f0\fswiss Helvetica;}
|
|
4
|
+
}
|
|
5
|
+
{\colortbl
|
|
6
|
+
;
|
|
7
|
+
\red255\green255\blue255;
|
|
8
|
+
\red255\green0\blue0;
|
|
9
|
+
}
|
|
10
|
+
{\stylesheet
|
|
11
|
+
{\s1 \ql\ltrpar\absw5040\absh7200\phpg\pvpg\posx0\posy0\shading100\cbpat2\cf1 \spriority1 Emphasis Background;}
|
|
12
|
+
{\s2 \qc\ltrpar\brdrb\brdrth\brdrw60\brsp0\brdrcf1 \brdrt\brdrth\brdrw60\brsp0\brdrcf1\b\caps\cf1\fs30 \sbasedon0 \sautoupd \snext0 \sqformat \spriority2 Title;}
|
|
13
|
+
{\s3 \qc\ltrpar\caps\expnd20\cf1\fs24 \sqformat \spriority3 Subtitle;}
|
|
14
|
+
{\s4 \ql\sb200\sa40\keepn\ltrpar\b\ul\ulc2\fs24 \snext0 \sqformat \spriority4 Heading 1;}
|
|
15
|
+
{\s0 \ql\sa200\hyphpar\ltrpar\fs24 \sqformat \spriority5 Normal;}
|
|
16
|
+
{\s5 \ql\sl-540\ltrpar\box\brdrdot\brdrw20\brdrcf2\absw0\absh-576\pvpara\wraparound\dropcapli2\dropcapt1\fs56 \sqformat \spriority6 Drop Caps;}
|
|
17
|
+
{\*\cs6 \b\i\cf2 \additive \spriority7 Emphasis;}
|
|
18
|
+
}
|
|
19
|
+
{\info
|
|
20
|
+
{\createim\yr2017\mo7\dy31\hr22\min4}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
\hyphauto1\paperw12247\paperh15819\margl1440\margr1440\margt1440\margb1440
|
|
24
|
+
{\pard\s4 \ql\sb200\sa40\keepn\ltrpar\b\ul\ulc2\fs24
|
|
25
|
+
Redshirt Pocket Guide
|
|
26
|
+
\par}
|
|
27
|
+
{\pard\s0 \ql\sa200\hyphpar\ltrpar\fs24
|
|
28
|
+
3
|
|
29
|
+
{\super
|
|
30
|
+
rd
|
|
31
|
+
}
|
|
32
|
+
Edition
|
|
33
|
+
\par}
|
|
34
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'rrtf'
|
|
2
|
+
require 'JSON'
|
|
3
|
+
|
|
4
|
+
DIR = File.dirname(__FILE__)
|
|
5
|
+
|
|
6
|
+
raw_styles = JSON.parse File.read(DIR+'/resources/json/redshirt_styles.json')
|
|
7
|
+
rtf = RRTF::Document.new("stylesheet" => raw_styles)
|
|
8
|
+
styles = rtf.stylesheet.styles
|
|
9
|
+
|
|
10
|
+
rtf.paragraph(styles['H1']) << "Redshirt Pocket Guide"
|
|
11
|
+
rtf.paragraph(styles['BODY']) do |p|
|
|
12
|
+
p << "3"
|
|
13
|
+
# apply an anonymous character style
|
|
14
|
+
p.apply("superscript" => true) << "rd"
|
|
15
|
+
p << " Edition"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
File.open(DIR+'/10.rtf', 'w') { |file| file.write(rtf.to_rtf) }
|
|
Binary file
|
|
Binary file
|
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"type": "paragraph",
|
|
4
|
+
"id": "PRIMARY_BACKGROUND",
|
|
5
|
+
"name": "Emphasis Background",
|
|
6
|
+
"foreground_color": "#ffffff",
|
|
7
|
+
"position": {
|
|
8
|
+
"size": "3.5in,5in",
|
|
9
|
+
"horizontal_position": 0,
|
|
10
|
+
"vertical_position": 0,
|
|
11
|
+
"horizontal_reference": "PAGE",
|
|
12
|
+
"vertical_reference": "PAGE"
|
|
13
|
+
},
|
|
14
|
+
"shading": {
|
|
15
|
+
"background_color": "#ff0000"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
2
18
|
{
|
|
3
19
|
"type": "paragraph",
|
|
4
20
|
"id": "TITLE",
|
|
@@ -8,12 +24,37 @@
|
|
|
8
24
|
"next_style": "BODY",
|
|
9
25
|
"base_style": "BODY",
|
|
10
26
|
"justification": "CENTER",
|
|
11
|
-
"space_after": 100,
|
|
12
27
|
"bold": true,
|
|
13
|
-
"underline": "DOUBLE",
|
|
14
|
-
"underline_color": "#ff0000",
|
|
15
28
|
"uppercase": true,
|
|
16
|
-
"font_size":
|
|
29
|
+
"font_size": "15pt",
|
|
30
|
+
"foreground_color": "#ffffff",
|
|
31
|
+
"border": [
|
|
32
|
+
{
|
|
33
|
+
"sides": "BOTTOM",
|
|
34
|
+
"line_type": "THICK",
|
|
35
|
+
"width": "3pt",
|
|
36
|
+
"spacing": 0,
|
|
37
|
+
"color": "#ffffff"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"sides": "TOP",
|
|
41
|
+
"line_type": "THICK",
|
|
42
|
+
"width": "3pt",
|
|
43
|
+
"spacing": 0,
|
|
44
|
+
"color": "#ffffff"
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"type": "paragraph",
|
|
50
|
+
"id": "SUBTITLE",
|
|
51
|
+
"name": "Subtitle",
|
|
52
|
+
"primary": true,
|
|
53
|
+
"justification": "CENTER",
|
|
54
|
+
"font_size": "12pt",
|
|
55
|
+
"foreground_color": "#ffffff",
|
|
56
|
+
"character_spacing_offset": "5pt",
|
|
57
|
+
"uppercase": true
|
|
17
58
|
},
|
|
18
59
|
{
|
|
19
60
|
"type": "paragraph",
|
|
@@ -21,12 +62,13 @@
|
|
|
21
62
|
"name": "Heading 1",
|
|
22
63
|
"primary": true,
|
|
23
64
|
"next_style": "BODY",
|
|
24
|
-
"space_after":
|
|
25
|
-
"space_before":
|
|
65
|
+
"space_after": "2pt",
|
|
66
|
+
"space_before": "10pt",
|
|
67
|
+
"no_break_with_next": true,
|
|
26
68
|
"underline": "SINGLE",
|
|
27
69
|
"underline_color": "#ff0000",
|
|
28
70
|
"bold": true,
|
|
29
|
-
"font_size":
|
|
71
|
+
"font_size": "12pt"
|
|
30
72
|
},
|
|
31
73
|
{
|
|
32
74
|
"type": "paragraph",
|
|
@@ -35,9 +77,31 @@
|
|
|
35
77
|
"primary": true,
|
|
36
78
|
"default": true,
|
|
37
79
|
"justification": "LEFT",
|
|
38
|
-
"font_size":
|
|
80
|
+
"font_size": "12pt",
|
|
81
|
+
"space_after": "10pt",
|
|
39
82
|
"hyphenate": true
|
|
40
83
|
},
|
|
84
|
+
{
|
|
85
|
+
"type": "paragraph",
|
|
86
|
+
"id": "DROP_CAPS",
|
|
87
|
+
"name": "Drop Caps",
|
|
88
|
+
"primary": true,
|
|
89
|
+
"font_size": "28pt",
|
|
90
|
+
"line_spacing": "-27pt",
|
|
91
|
+
"position": {
|
|
92
|
+
"drop_cap_lines": 2,
|
|
93
|
+
"drop_cap_type": "IN_TEXT",
|
|
94
|
+
"text_wrap": "AROUND",
|
|
95
|
+
"vertical_reference": "PARAGRAPH",
|
|
96
|
+
"size": "0pt,-28.8pt"
|
|
97
|
+
},
|
|
98
|
+
"border": {
|
|
99
|
+
"sides": "ALL",
|
|
100
|
+
"line_type": "DOT",
|
|
101
|
+
"width": "1pt",
|
|
102
|
+
"color": "#ff0000"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
41
105
|
{
|
|
42
106
|
"type": "character",
|
|
43
107
|
"id": "EMPH",
|
data/examples/~$01.rtf
ADDED
|
Binary file
|
data/lib/rrtf.rb
CHANGED
|
@@ -1,27 +1,15 @@
|
|
|
1
1
|
require 'rrtf/version'
|
|
2
|
+
require 'rrtf/utilities'
|
|
2
3
|
require 'rrtf/font'
|
|
3
4
|
require 'rrtf/colour'
|
|
5
|
+
require 'rrtf/page'
|
|
6
|
+
require 'rrtf/formatting'
|
|
7
|
+
require 'rrtf/properties'
|
|
4
8
|
require 'rrtf/style'
|
|
5
9
|
require 'rrtf/stylesheet'
|
|
6
10
|
require 'rrtf/information'
|
|
7
|
-
require 'rrtf/paper'
|
|
8
11
|
require 'rrtf/node'
|
|
9
12
|
require 'rrtf/list'
|
|
10
13
|
|
|
11
14
|
module RRTF
|
|
12
|
-
class RTFError < StandardError
|
|
13
|
-
def initialize(message=nil)
|
|
14
|
-
super(message == nil ? 'No error message available.' : message)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def RTFError.fire(message=nil)
|
|
18
|
-
raise RTFError.new(message)
|
|
19
|
-
end
|
|
20
|
-
end # class RTFError
|
|
21
|
-
|
|
22
|
-
class Utilities
|
|
23
|
-
def self.constantize(string)
|
|
24
|
-
string.split('::').inject(Object) {|o,c| o.const_get c}
|
|
25
|
-
end
|
|
26
|
-
end # class Utilities
|
|
27
15
|
end # module RRTF
|
data/lib/rrtf/colour.rb
CHANGED
|
@@ -80,6 +80,14 @@ module RRTF
|
|
|
80
80
|
prefix = indent > 0 ? ' ' * indent : ''
|
|
81
81
|
"#{prefix}\\red#{@red}\\green#{@green}\\blue#{@blue};"
|
|
82
82
|
end
|
|
83
|
+
|
|
84
|
+
def to_decimal(options = {})
|
|
85
|
+
if options["reverse_bytes"]
|
|
86
|
+
(@blue * 65536) + (@green * 256) + @red
|
|
87
|
+
else
|
|
88
|
+
(@red * 65536) + (@green * 256) + @blue
|
|
89
|
+
end # if
|
|
90
|
+
end
|
|
83
91
|
end # End of the Colour class.
|
|
84
92
|
|
|
85
93
|
|
|
@@ -0,0 +1,988 @@
|
|
|
1
|
+
require 'stringio'
|
|
2
|
+
|
|
3
|
+
# Character formatting attributes & methods shared between style types.
|
|
4
|
+
# @author Wesley Hileman
|
|
5
|
+
# @since 0.0.2
|
|
6
|
+
module RRTF::CharacterFormatting
|
|
7
|
+
# Formatting attributes that can be applied to any text in an RTF document.
|
|
8
|
+
# @return [Hash<String, Hash>] a hash mapping each attribute to a hash that
|
|
9
|
+
# describes (1) the attribute's default value, (2) how to parse the attribute
|
|
10
|
+
# from the user, and (3) how to convert the attribute to an RTF sequence.
|
|
11
|
+
CHARACTER_ATTRIBUTES = {
|
|
12
|
+
# toggable attributes
|
|
13
|
+
"bold" => {
|
|
14
|
+
"default" => nil,
|
|
15
|
+
"to_rtf" => lambda{ |value, document| (value ? '\b' : '\b0') unless value.nil? }
|
|
16
|
+
},
|
|
17
|
+
"italic" => {
|
|
18
|
+
"default" => nil,
|
|
19
|
+
"to_rtf" => lambda{ |value, document| (value ? '\i' : '\i0') unless value.nil? }
|
|
20
|
+
},
|
|
21
|
+
"underline" => {
|
|
22
|
+
"default" => nil,
|
|
23
|
+
"dictionary" => {
|
|
24
|
+
"SINGLE" => "",
|
|
25
|
+
"DOUBLE" => "db",
|
|
26
|
+
"THICK" => "th",
|
|
27
|
+
"DASH" => "dash",
|
|
28
|
+
"LONG_DASH" => "ldash",
|
|
29
|
+
"DOT" => "d",
|
|
30
|
+
"DASH_DOT" => "dashd",
|
|
31
|
+
"DASH_DOT_DOT" => "dashdd",
|
|
32
|
+
"WAVE" => 'wave',
|
|
33
|
+
"THICK_DASH" => "thdash",
|
|
34
|
+
"THICK_LONG_DASH" => "thldash",
|
|
35
|
+
"THICK_DOT" => "thd",
|
|
36
|
+
"THICK_DASH_DOT" => "thdashd",
|
|
37
|
+
"THICK_DASH_DOT_DOT" => "thdashdd",
|
|
38
|
+
"THICK_WAVE" => 'hwave',
|
|
39
|
+
"DOUBLE_WAVE" => 'uldbwave'
|
|
40
|
+
},
|
|
41
|
+
"to_rtf" => lambda do |value, document|
|
|
42
|
+
return if value.nil?
|
|
43
|
+
case value
|
|
44
|
+
when TrueClass
|
|
45
|
+
'\ul'
|
|
46
|
+
when FalseClass
|
|
47
|
+
'\ulnone'
|
|
48
|
+
when String
|
|
49
|
+
"\\ul#{value}"
|
|
50
|
+
end # case
|
|
51
|
+
end
|
|
52
|
+
},
|
|
53
|
+
"uppercase" => {
|
|
54
|
+
"default" => nil,
|
|
55
|
+
"to_rtf" => lambda{ |value, document| (value ? '\caps' : '\caps0') unless value.nil? }
|
|
56
|
+
},
|
|
57
|
+
"superscript" => {
|
|
58
|
+
"default" => nil,
|
|
59
|
+
"to_rtf" => lambda{ |value, document| (value ? '\super' : '\super0') unless value.nil? }
|
|
60
|
+
},
|
|
61
|
+
"subscript" => {
|
|
62
|
+
"default" => nil,
|
|
63
|
+
"to_rtf" => lambda{ |value, document| (value ? '\sub' : '\sub0') unless value.nil? }
|
|
64
|
+
},
|
|
65
|
+
"strike" => {
|
|
66
|
+
"default" => nil,
|
|
67
|
+
"to_rtf" => lambda{ |value, document| (value ? '\strike' : '\strike0') unless value.nil? }
|
|
68
|
+
},
|
|
69
|
+
"emboss" => {
|
|
70
|
+
"default" => nil,
|
|
71
|
+
"to_rtf" => lambda{ |value, document| (value ? '\embo' : '\embo0') unless value.nil? }
|
|
72
|
+
},
|
|
73
|
+
"imprint" => {
|
|
74
|
+
"default" => nil,
|
|
75
|
+
"to_rtf" => lambda{ |value, document| (value ? '\impr' : '\impr0') unless value.nil? }
|
|
76
|
+
},
|
|
77
|
+
"outline" => {
|
|
78
|
+
"default" => nil,
|
|
79
|
+
"to_rtf" => lambda{ |value, document| (value ? '\outl' : '\outl0') unless value.nil? }
|
|
80
|
+
},
|
|
81
|
+
"text_hidden" => {
|
|
82
|
+
"default" => nil,
|
|
83
|
+
"to_rtf" => lambda{ |value, document| (value ? '\v' : '\v0') unless value.nil? }
|
|
84
|
+
},
|
|
85
|
+
"kerning" => {
|
|
86
|
+
"default" => nil,
|
|
87
|
+
"to_rtf" => lambda{ |value, document| (value.is_a?(Integer) ? "\\kerning#{value}" : '\kerning0') unless value.nil? }
|
|
88
|
+
},
|
|
89
|
+
# non-toggable attributes
|
|
90
|
+
"character_spacing_offset" => {
|
|
91
|
+
"default" => nil,
|
|
92
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2quarterpt(value) },
|
|
93
|
+
"to_rtf" => lambda{ |value, document| "\\expnd#{value}" unless value.nil? }
|
|
94
|
+
},
|
|
95
|
+
"foreground_color" => {
|
|
96
|
+
"default" => nil,
|
|
97
|
+
"from_user" => lambda{ |value| value.is_a?(RRTF::Colour) ? value : RRTF::Colour.from_string(value) },
|
|
98
|
+
"to_rtf" => lambda{ |value, document| "\\cf#{document.colours.index(value)}" unless value.nil? }
|
|
99
|
+
},
|
|
100
|
+
"background_color" => {
|
|
101
|
+
"default" => nil,
|
|
102
|
+
"from_user" => lambda{ |value| value.is_a?(RRTF::Colour) ? value : RRTF::Colour.from_string(value) },
|
|
103
|
+
"to_rtf" => lambda{ |value, document| "\\cb#{document.colours.index(value)}" unless value.nil? }
|
|
104
|
+
},
|
|
105
|
+
"underline_color" => {
|
|
106
|
+
"default" => nil,
|
|
107
|
+
"from_user" => lambda{ |value| value.is_a?(RRTF::Colour) ? value : RRTF::Colour.from_string(value) },
|
|
108
|
+
"to_rtf" => lambda{ |value, document| "\\ulc#{document.colours.index(value)}" unless value.nil? }
|
|
109
|
+
},
|
|
110
|
+
"highlight_color" => {
|
|
111
|
+
"default" => nil,
|
|
112
|
+
"from_user" => lambda{ |value| value.is_a?(RRTF::Colour) ? value : RRTF::Colour.from_string(value) },
|
|
113
|
+
"to_rtf" => lambda{ |value, document| "\\highlight#{document.colours.index(value)}" unless value.nil? }
|
|
114
|
+
},
|
|
115
|
+
"font" => {
|
|
116
|
+
"default" => nil,
|
|
117
|
+
"from_user" => lambda{ |value| value.is_a?(RRTF::Font) ? value : RRTF::Font.from_string(value) },
|
|
118
|
+
"to_rtf" => lambda{ |value, document| "\\f#{document.fonts.index(value)}" unless value.nil? }
|
|
119
|
+
},
|
|
120
|
+
"font_size" => {
|
|
121
|
+
"default" => nil,
|
|
122
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2halfpt(value) },
|
|
123
|
+
"to_rtf" => lambda{ |value, document| "\\fs#{value}" unless value.nil? }
|
|
124
|
+
}
|
|
125
|
+
}.freeze
|
|
126
|
+
|
|
127
|
+
# Generates attribute accessors for all character attributes when the module
|
|
128
|
+
# is included in another module or class.
|
|
129
|
+
def self.included(base)
|
|
130
|
+
# define accessors in base for paragraph attributes
|
|
131
|
+
base.class_eval do
|
|
132
|
+
CHARACTER_ATTRIBUTES.each do |key, options|
|
|
133
|
+
attr_accessor :"#{key}"
|
|
134
|
+
end # each
|
|
135
|
+
end # class_eval
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Initializes character formatting attributes.
|
|
139
|
+
# @note The RTF specification states the "highlight_color" attribute can not
|
|
140
|
+
# be applied to a style definition in a stylesheet.
|
|
141
|
+
#
|
|
142
|
+
# @param [Hash] options the character formatting options.
|
|
143
|
+
# @option options [Boolean] "bold" (nil) enable or disable bold (nil to remain same).
|
|
144
|
+
# @option options [Boolean] "italic" (nil) enable or disable italic (nil to remain same).
|
|
145
|
+
# @option options [Boolean, String] "underline" (nil) enable or disable underline (nil to remain same); can also be a string (see {CharacterFormatting::CHARACTER_ATTRIBUTES}).
|
|
146
|
+
# @option options [Boolean] "uppercase" (nil) enable or disable all caps (nil to remain same).
|
|
147
|
+
# @option options [Boolean] "superscript" (nil) enable or disable superscript (nil to remain same).
|
|
148
|
+
# @option options [Boolean] "subscript" (nil) enable or disable subscript (nil to remain same).
|
|
149
|
+
# @option options [Boolean] "strike" (nil) enable or disable single line-through (nil to remain same).
|
|
150
|
+
# @option options [Boolean] "emboss" (nil) enable or disable emboss (nil to remain same).
|
|
151
|
+
# @option options [Boolean] "imprint" (nil) enable or disable imprint (nil to remain same).
|
|
152
|
+
# @option options [Boolean] "outline" (nil) enable or disable outline (nil to remain same).
|
|
153
|
+
# @option options [Boolean] "text_hidden" (nil) enable or disable hidden (nil to remain same).
|
|
154
|
+
# @option options [Boolean, Integer] "kerning" (nil) enable or disable kerning (nil to remain same); to enable specify the font size in half-points above which kerining will be applied.
|
|
155
|
+
# @option options [Integer] "character_spacing_offset" (nil) quarter points by which to expand or compress character spacing (negative for compress).
|
|
156
|
+
# @option options [String, Colour] "foreground_color" (nil) colour to apply to the foreground (text); see {Colour.from_string} for string format.
|
|
157
|
+
# @option options [String, Colour] "background_color" (nil) colour to apply to the background; see {Colour.from_string} for string format.
|
|
158
|
+
# @option options [String, Colour] "underline_color" (nil) colour to apply to the underline; see {Colour.from_string} for string format.
|
|
159
|
+
# @option options [String, Colour] "highlight_color" (nil) colour with which to highlight text.
|
|
160
|
+
# @option options [String, Font] "font" (nil) font to apply to text; see {Font.from_string} for string format.
|
|
161
|
+
# @option options [Integer] "font_size" (nil) font size in half-points.
|
|
162
|
+
def initialize_character_formatting(options = {})
|
|
163
|
+
# load default attribute values
|
|
164
|
+
CHARACTER_ATTRIBUTES.each do |key, options|
|
|
165
|
+
send("#{key}=", options["default"])
|
|
166
|
+
end # each
|
|
167
|
+
# overwrite default attribute values with given values
|
|
168
|
+
set_character_formatting_from_hashmap(options)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Sets character formatting attributes according to the supplied hashmap.
|
|
172
|
+
# @see #initialize_character_formatting
|
|
173
|
+
def set_character_formatting_from_hashmap(hash)
|
|
174
|
+
hash.each do |attribute, value|
|
|
175
|
+
# skip unreconized attributes
|
|
176
|
+
next unless(CHARACTER_ATTRIBUTES.keys.include?(attribute))
|
|
177
|
+
# preprocess value if nessesary
|
|
178
|
+
if CHARACTER_ATTRIBUTES[attribute].has_key?("from_user")
|
|
179
|
+
value = CHARACTER_ATTRIBUTES[attribute]["from_user"].call(value)
|
|
180
|
+
elsif CHARACTER_ATTRIBUTES[attribute].has_key?("dictionary") && value.is_a?(String)
|
|
181
|
+
value = CHARACTER_ATTRIBUTES[attribute]["dictionary"][value]
|
|
182
|
+
end # if
|
|
183
|
+
# set attribute value
|
|
184
|
+
send("#{attribute}=", value)
|
|
185
|
+
end # each
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Generates an RTF string representing all applied character formatting.
|
|
189
|
+
# @note To generate correct RTF control words for colours and fonts, a
|
|
190
|
+
# document object must be provided to this method so that colour and font
|
|
191
|
+
# indicies may be found in the document's colour and font tables, respectively.
|
|
192
|
+
#
|
|
193
|
+
# @param [Document] document the document for which the RTF is to be generated.
|
|
194
|
+
def character_formatting_to_rtf(document = nil)
|
|
195
|
+
text = StringIO.new
|
|
196
|
+
|
|
197
|
+
# accumulate RTF representations of attributes
|
|
198
|
+
CHARACTER_ATTRIBUTES.each do |key, options|
|
|
199
|
+
if options.has_key?("to_rtf")
|
|
200
|
+
rtf = options["to_rtf"].call(send(key), document)
|
|
201
|
+
text << rtf unless rtf.nil?
|
|
202
|
+
end # if
|
|
203
|
+
end # each
|
|
204
|
+
|
|
205
|
+
text.string
|
|
206
|
+
end
|
|
207
|
+
end # module CharacterFormatting
|
|
208
|
+
|
|
209
|
+
# Paragraph formatting attributes and methods shared between style types.
|
|
210
|
+
# @author Wesley Hileman
|
|
211
|
+
# @since 0.0.2
|
|
212
|
+
module RRTF::ParagraphFormatting
|
|
213
|
+
# Formatting attributes that can be applied to any paragraph in an RTF document.
|
|
214
|
+
# @return [Hash<String, Hash>] a hash mapping each attribute to a hash that
|
|
215
|
+
# describes (1) the attribute's default value, (2) how to parse the attribute
|
|
216
|
+
# from the user, and (3) how to convert the attribute to an RTF sequence.
|
|
217
|
+
PARAGRAPH_ATTRIBUTES = {
|
|
218
|
+
"justification" => {
|
|
219
|
+
"default" => "l",
|
|
220
|
+
"dictionary" => {
|
|
221
|
+
"LEFT" => "l",
|
|
222
|
+
"RIGHT" => "r",
|
|
223
|
+
"CENTER" => "c",
|
|
224
|
+
"CENTRE" => "c",
|
|
225
|
+
"FULL" => "j"
|
|
226
|
+
},
|
|
227
|
+
"to_rtf" => lambda{ |value, document| "\\q#{value}" }
|
|
228
|
+
},
|
|
229
|
+
"left_indent" => {
|
|
230
|
+
"default" => nil,
|
|
231
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2twips(value) },
|
|
232
|
+
"to_rtf" => lambda{ |value, document| "\\li#{value}" unless value.nil? }
|
|
233
|
+
},
|
|
234
|
+
"right_indent" => {
|
|
235
|
+
"default" => nil,
|
|
236
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2twips(value) },
|
|
237
|
+
"to_rtf" => lambda{ |value, document| "\\ri#{value}" unless value.nil? }
|
|
238
|
+
},
|
|
239
|
+
"first_line_indent" => {
|
|
240
|
+
"default" => nil,
|
|
241
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2twips(value) },
|
|
242
|
+
"to_rtf" => lambda{ |value, document| "\\fi#{value}" unless value.nil? }
|
|
243
|
+
},
|
|
244
|
+
"space_before" => {
|
|
245
|
+
"default" => nil,
|
|
246
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2twips(value) },
|
|
247
|
+
"to_rtf" => lambda{ |value, document| "\\sb#{value}" unless value.nil? }
|
|
248
|
+
},
|
|
249
|
+
"space_after" => {
|
|
250
|
+
"default" => nil,
|
|
251
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2twips(value) },
|
|
252
|
+
"to_rtf" => lambda{ |value, document| "\\sa#{value}" unless value.nil? }
|
|
253
|
+
},
|
|
254
|
+
"line_spacing" => {
|
|
255
|
+
"default" => nil,
|
|
256
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2twips(value) },
|
|
257
|
+
"to_rtf" => lambda{ |value, document| "\\sl#{value}" unless value.nil? }
|
|
258
|
+
},
|
|
259
|
+
"widow_orphan_ctl" => {
|
|
260
|
+
"default" => nil,
|
|
261
|
+
"to_rtf" => lambda{ |value, document| (value ? "\\widctlpar" : "\\nowidctlpar") unless value.nil? }
|
|
262
|
+
},
|
|
263
|
+
"no_break" => {
|
|
264
|
+
"default" => false,
|
|
265
|
+
"to_rtf" => lambda{ |value, document| "\\keep" if value }
|
|
266
|
+
},
|
|
267
|
+
"no_break_with_next" => {
|
|
268
|
+
"default" => false,
|
|
269
|
+
"to_rtf" => lambda{ |value, document| "\\keepn" if value }
|
|
270
|
+
},
|
|
271
|
+
"hyphenate" => {
|
|
272
|
+
"default" => nil,
|
|
273
|
+
"to_rtf" => lambda{ |value, document| (value ? "\\hyphpar" : "\\hyphpar0") unless value.nil? }
|
|
274
|
+
},
|
|
275
|
+
"paragraph_flow" => {
|
|
276
|
+
"default" => 'ltr',
|
|
277
|
+
"dictionary" => {
|
|
278
|
+
"LEFT_TO_RIGHT" => 'ltr',
|
|
279
|
+
"RIGHT_TO_LEFT" => 'rtl'
|
|
280
|
+
},
|
|
281
|
+
"to_rtf" => lambda{ |value, document| "\\#{value}par" unless value.nil? }
|
|
282
|
+
},
|
|
283
|
+
"border" => {
|
|
284
|
+
"default" => nil,
|
|
285
|
+
"from_user" => lambda do |value|
|
|
286
|
+
case value
|
|
287
|
+
when Array
|
|
288
|
+
value.collect do |b|
|
|
289
|
+
case b
|
|
290
|
+
when Hash
|
|
291
|
+
RRTF::BorderStyle.new(b)
|
|
292
|
+
when RRTF::BorderStyle
|
|
293
|
+
b
|
|
294
|
+
else
|
|
295
|
+
RRTF::RTFError.fire("Invalid border '#{b}'.")
|
|
296
|
+
end # case
|
|
297
|
+
end # collect
|
|
298
|
+
when Hash
|
|
299
|
+
[RRTF::BorderStyle.new(value)]
|
|
300
|
+
when RRTF::BorderStyle
|
|
301
|
+
[value]
|
|
302
|
+
else
|
|
303
|
+
RRTF::RTFError.fire("Invalid border '#{value}'.")
|
|
304
|
+
end # case
|
|
305
|
+
end,
|
|
306
|
+
"to_rtf" => lambda{ |value, document| value.collect{ |border| border.rtf_formatting(document) }.join(' ') unless value.nil? }
|
|
307
|
+
},
|
|
308
|
+
"position" => {
|
|
309
|
+
"default" => nil,
|
|
310
|
+
"from_user" => lambda do |value|
|
|
311
|
+
case value
|
|
312
|
+
when Hash
|
|
313
|
+
RRTF::PositionStyle.new(value)
|
|
314
|
+
when PositionStyle
|
|
315
|
+
value
|
|
316
|
+
else
|
|
317
|
+
RRTF::RTFError.fire("Invalid position '#{value}'.")
|
|
318
|
+
end # case
|
|
319
|
+
end,
|
|
320
|
+
"to_rtf" => lambda{ |value, document| value.rtf_formatting(document) unless value.nil? }
|
|
321
|
+
},
|
|
322
|
+
"shading" => {
|
|
323
|
+
"default" => nil,
|
|
324
|
+
"from_user" => lambda do |value|
|
|
325
|
+
case value
|
|
326
|
+
when Hash
|
|
327
|
+
RRTF::ShadingStyle.new(value)
|
|
328
|
+
when ShadingStyle
|
|
329
|
+
value
|
|
330
|
+
else
|
|
331
|
+
RRTF::RTFError.fire("Invalid shading '#{value}'.")
|
|
332
|
+
end # case
|
|
333
|
+
end,
|
|
334
|
+
"to_rtf" => lambda{ |value, document| value.rtf_formatting(document) unless value.nil? }
|
|
335
|
+
}
|
|
336
|
+
}.freeze
|
|
337
|
+
|
|
338
|
+
# Generates attribute accessors for all paragraph attributes when the module
|
|
339
|
+
# is included in another module or class.
|
|
340
|
+
def self.included(base)
|
|
341
|
+
# define accessors in base for paragraph attributes
|
|
342
|
+
base.class_eval do
|
|
343
|
+
PARAGRAPH_ATTRIBUTES.each do |key, options|
|
|
344
|
+
attr_accessor :"#{key}"
|
|
345
|
+
end # each
|
|
346
|
+
end # class_eval
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Initializes paragraph formatting attributes.
|
|
350
|
+
#
|
|
351
|
+
# @param [Hash] options the paragraph formatting options.
|
|
352
|
+
# @option options [String] "justification" ('LEFT') the paragraph justification ('LEFT', 'CENTER'/'CENTRE', 'RIGHT', or 'FULL').
|
|
353
|
+
# @option options [Integer] "left_indent" (nil) the left indent of the paragraph (twentieth points).
|
|
354
|
+
# @option options [Integer] "right_indent" (nil) the right indent of the paragraph (twentieth points).
|
|
355
|
+
# @option options [Integer] "first_line_indent" (nil) the first line indent of the paragraph (twentieth points).
|
|
356
|
+
# @option options [Integer] "space_before" (nil) the space before the paragraph (twentieth points).
|
|
357
|
+
# @option options [Integer] "space_after" (nil) the space after the paragraph (twentieth points).
|
|
358
|
+
# @option options [Integer] "line_spacing" (nil) the line spacing in the paragraph (twentieth points).
|
|
359
|
+
# @option options [Boolean] "widow_orphan_ctl" (nil) enable or disable widow-and-orphan control.
|
|
360
|
+
# @option options [Boolean] "no_break" (nil) when true, tries to keep the paragraph on the same page (i.e. without breaking).
|
|
361
|
+
# @option options [Boolean] "no_break_with_next" (nil) when true, tries to keep the paragraph with the next paragraph on the same page (i.e. without breaking).
|
|
362
|
+
# @option options [Boolean] "hyphenate" (nil) enable or disable hyphenation for the paragraph.
|
|
363
|
+
# @option options [String] "paragraph_flow" ('LEFT_TO_RIGHT') the text flow direction in the paragraph ('LEFT_TO_RIGHT' or 'RIGHT_TO_LEFT').
|
|
364
|
+
# @option options [Array<Hash, BorderStyle>, Hash, BorderStyle] "border" (nil) the border style(s) to be applied to the paragraph (see {BorderFormatting#initialize_border_formatting}).
|
|
365
|
+
def initialize_paragraph_formatting(options = {})
|
|
366
|
+
# load default attribute values
|
|
367
|
+
PARAGRAPH_ATTRIBUTES.each do |key, options|
|
|
368
|
+
send("#{key}=", options["default"])
|
|
369
|
+
end # each
|
|
370
|
+
# overwrite default attribute values with given values
|
|
371
|
+
set_paragraph_formatting_from_hashmap(options)
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# Sets paragraph formatting attributes according to the supplied hashmap.
|
|
375
|
+
# @see #initialize_document_formatting
|
|
376
|
+
def set_paragraph_formatting_from_hashmap(hash)
|
|
377
|
+
hash.each do |attribute, value|
|
|
378
|
+
# skip unreconized attributes
|
|
379
|
+
next unless(PARAGRAPH_ATTRIBUTES.keys.include?(attribute))
|
|
380
|
+
# preprocess value if nessesary
|
|
381
|
+
if PARAGRAPH_ATTRIBUTES[attribute].has_key?("from_user")
|
|
382
|
+
value = PARAGRAPH_ATTRIBUTES[attribute]["from_user"].call(value)
|
|
383
|
+
elsif PARAGRAPH_ATTRIBUTES[attribute].has_key?("dictionary") && value.is_a?(String)
|
|
384
|
+
value = PARAGRAPH_ATTRIBUTES[attribute]["dictionary"][value]
|
|
385
|
+
end # if
|
|
386
|
+
# set attribute value
|
|
387
|
+
send("#{attribute}=", value)
|
|
388
|
+
end # each
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# Generates an RTF string representing all applied paragraph formatting.
|
|
392
|
+
# @note To generate correct RTF control words for colours and fonts, a
|
|
393
|
+
# document object must be provided to this method so that colour and font
|
|
394
|
+
# indicies may be found in the document's colour and font tables, respectively.
|
|
395
|
+
#
|
|
396
|
+
# @param [Document] document the document for which the RTF is to be generated.
|
|
397
|
+
def paragraph_formatting_to_rtf(document)
|
|
398
|
+
text = StringIO.new
|
|
399
|
+
|
|
400
|
+
# accumulate RTF representations of paragraph attributes
|
|
401
|
+
PARAGRAPH_ATTRIBUTES.each do |key, options|
|
|
402
|
+
if options.has_key?("to_rtf")
|
|
403
|
+
rtf = options["to_rtf"].call(send(key), document)
|
|
404
|
+
text << rtf unless rtf.nil?
|
|
405
|
+
end # if
|
|
406
|
+
end # each
|
|
407
|
+
|
|
408
|
+
text.string
|
|
409
|
+
end
|
|
410
|
+
end # module ParagraphFormatting
|
|
411
|
+
|
|
412
|
+
# Paragraph, table, and image border formatting attributes and methods.
|
|
413
|
+
# @author Wesley Hileman
|
|
414
|
+
# @since 1.0.0
|
|
415
|
+
module RRTF::BorderFormatting
|
|
416
|
+
# Formatting attributes that can be applied to borders of paragraphs, tables, & images.
|
|
417
|
+
# @note The "sides" attribute must appear at the top of this hash so that
|
|
418
|
+
# {#border_formatting_to_rtf} generates correct RTF (borders are initiated by the "sides"
|
|
419
|
+
# attribute in the RTF spec).
|
|
420
|
+
# @note The "line_type" attribute must appear second in this hash so that
|
|
421
|
+
# {#border_formatting_to_rtf} generates correct RTF.
|
|
422
|
+
BORDER_ATTRIBUTES = {
|
|
423
|
+
"sides" => {
|
|
424
|
+
"default" => "box",
|
|
425
|
+
"dictionary" => {
|
|
426
|
+
"ALL" => "box",
|
|
427
|
+
"LEFT" => "brdrl",
|
|
428
|
+
"RIGHT" => "brdrr",
|
|
429
|
+
"TOP" => "brdrt",
|
|
430
|
+
"BOTTOM" => "brdrb"
|
|
431
|
+
},
|
|
432
|
+
"to_rtf" => lambda{ |value, document| "\\#{value}" unless value.nil? }
|
|
433
|
+
},
|
|
434
|
+
"line_type" => {
|
|
435
|
+
"default" => "brdrs",
|
|
436
|
+
"dictionary" => {
|
|
437
|
+
"SINGLE" => "brdrs",
|
|
438
|
+
"THICK" => "brdrth",
|
|
439
|
+
"DOUBLE" => "brdrdb",
|
|
440
|
+
"DOT" => "brdrdot",
|
|
441
|
+
"DASH" => "brdrdash",
|
|
442
|
+
"HAIRLINE" => "brdrhair"
|
|
443
|
+
},
|
|
444
|
+
"to_rtf" => lambda{ |value, document| "\\#{value}" unless value.nil? }
|
|
445
|
+
},
|
|
446
|
+
"width" => {
|
|
447
|
+
"default" => nil,
|
|
448
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2twips(value) },
|
|
449
|
+
"to_rtf" => lambda{ |value, document| "\\brdrw#{value}" unless value.nil? }
|
|
450
|
+
},
|
|
451
|
+
"spacing" => {
|
|
452
|
+
"default" => nil,
|
|
453
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2twips(value) },
|
|
454
|
+
"to_rtf" => lambda{ |value, document| "\\brsp#{value}" unless value.nil? }
|
|
455
|
+
},
|
|
456
|
+
"color" => {
|
|
457
|
+
"default" => nil,
|
|
458
|
+
"from_user" => lambda{ |value| value.is_a?(RRTF::Colour) ? value : RRTF::Colour.from_string(value) },
|
|
459
|
+
"to_rtf" => lambda{ |value, document| "\\brdrcf#{document.colours.index(value)}" unless value.nil? }
|
|
460
|
+
}
|
|
461
|
+
}.freeze
|
|
462
|
+
|
|
463
|
+
# Generates attribute accessors for all paragraph attributes when the module
|
|
464
|
+
# is included in another module or class.
|
|
465
|
+
def self.included(base)
|
|
466
|
+
# define accessors in base for paragraph attributes
|
|
467
|
+
base.class_eval do
|
|
468
|
+
BORDER_ATTRIBUTES.each do |key, options|
|
|
469
|
+
attr_accessor :"#{key}"
|
|
470
|
+
end # each
|
|
471
|
+
end # class_eval
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
# Initializes border formatting attributes.
|
|
475
|
+
#
|
|
476
|
+
# @param [Hash] options the border formatting options.
|
|
477
|
+
# @option options [String] "sides" ('ALL') the sides to which the border applied ("ALL", "LEFT", "RIGHT", "TOP", or "BOTTOM").
|
|
478
|
+
# @option options [String] "line_type" ('SINGLE') the border line type ("SINGLE", "THICK", "DOUBLE", "DOT", "DASH", or "HAIRLINE").
|
|
479
|
+
# @option options [String] "width" (nil) the width of the the border line in twips (can be a string, see {Utilities.value2twips}).
|
|
480
|
+
# @option options [String] "spacing" (nil) the spacing between the border and paragraph content in twips (can be a string, see {Utilities.value2twips}).
|
|
481
|
+
# @option options [String, Colour] "color" (nil) the color of the the border line (can be a string, see {Colour.from_string}).
|
|
482
|
+
def initialize_border_formatting(options = {})
|
|
483
|
+
# load default attribute values
|
|
484
|
+
BORDER_ATTRIBUTES.each do |key, options|
|
|
485
|
+
send("#{key}=", options["default"])
|
|
486
|
+
end # each
|
|
487
|
+
# overwrite default attribute values with given values
|
|
488
|
+
set_border_formatting_from_hashmap(options)
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
# Sets paragraph formatting attributes according to the supplied hashmap.
|
|
492
|
+
# @see #initialize_border_formatting
|
|
493
|
+
def set_border_formatting_from_hashmap(hash)
|
|
494
|
+
hash.each do |attribute, value|
|
|
495
|
+
# skip unreconized attributes
|
|
496
|
+
next unless(BORDER_ATTRIBUTES.keys.include?(attribute))
|
|
497
|
+
# preprocess value if nessesary
|
|
498
|
+
if BORDER_ATTRIBUTES[attribute].has_key?("from_user")
|
|
499
|
+
value = BORDER_ATTRIBUTES[attribute]["from_user"].call(value)
|
|
500
|
+
elsif BORDER_ATTRIBUTES[attribute].has_key?("dictionary") && value.is_a?(String)
|
|
501
|
+
value = BORDER_ATTRIBUTES[attribute]["dictionary"][value]
|
|
502
|
+
end # if
|
|
503
|
+
# set attribute value
|
|
504
|
+
send("#{attribute}=", value)
|
|
505
|
+
end # each
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
# Generates an RTF string representing all applied border formatting.
|
|
509
|
+
# @note To generate correct RTF control words for colours and fonts, a
|
|
510
|
+
# document object must be provided to this method so that colour and font
|
|
511
|
+
# indicies may be found in the document's colour and font tables, respectively.
|
|
512
|
+
#
|
|
513
|
+
# @param [Document] document the document for which the RTF is to be generated.
|
|
514
|
+
def border_formatting_to_rtf(document)
|
|
515
|
+
text = StringIO.new
|
|
516
|
+
|
|
517
|
+
# accumulate RTF representations of paragraph attributes
|
|
518
|
+
BORDER_ATTRIBUTES.each do |key, options|
|
|
519
|
+
if options.has_key?("to_rtf")
|
|
520
|
+
rtf = options["to_rtf"].call(send(key), document)
|
|
521
|
+
text << rtf unless rtf.nil?
|
|
522
|
+
end # if
|
|
523
|
+
end # each
|
|
524
|
+
|
|
525
|
+
text.string
|
|
526
|
+
end
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
# Paragraph absolute positioning formatting attributes and methods.
|
|
530
|
+
# @author Wesley Hileman
|
|
531
|
+
# @since 1.0.0
|
|
532
|
+
module RRTF::PositionFormatting
|
|
533
|
+
# Formatting attributes that can be applied to position paragraphs as frames.
|
|
534
|
+
POSITION_ATTRIBUTES = {
|
|
535
|
+
"size" => {
|
|
536
|
+
"default" => nil,
|
|
537
|
+
"from_user" => lambda{ |value| RRTF::Page::Size.new(value) },
|
|
538
|
+
"to_rtf" => lambda{ |value, document| "\\absw#{value.width}\\absh#{value.height}" unless value.nil? }
|
|
539
|
+
},
|
|
540
|
+
"horizontal_reference" => {
|
|
541
|
+
"default" => nil,
|
|
542
|
+
"dictionary" => {
|
|
543
|
+
"PAGE" => "phpg",
|
|
544
|
+
"MARGIN" => "phmrg",
|
|
545
|
+
"COLUMN" => "phcol"
|
|
546
|
+
},
|
|
547
|
+
"to_rtf" => lambda{ |value, document| "\\#{value}" unless value.nil? }
|
|
548
|
+
},
|
|
549
|
+
"vertical_reference" => {
|
|
550
|
+
"default" => nil,
|
|
551
|
+
"dictionary" => {
|
|
552
|
+
"PAGE" => "pvpg",
|
|
553
|
+
"MARGIN" => "pvmrg",
|
|
554
|
+
"PARAGRAPH" => "pvpara"
|
|
555
|
+
},
|
|
556
|
+
"to_rtf" => lambda{ |value, document| "\\#{value}" unless value.nil? }
|
|
557
|
+
},
|
|
558
|
+
"horizontal_position" => {
|
|
559
|
+
"default" => nil,
|
|
560
|
+
"dictionary" => {
|
|
561
|
+
"CENTER" => "posxc",
|
|
562
|
+
"LEFT" => "posxl",
|
|
563
|
+
"RIGHT" => "posxr"
|
|
564
|
+
},
|
|
565
|
+
"from_user" => lambda do |value|
|
|
566
|
+
return nil if value.nil?
|
|
567
|
+
if value.is_a?(String) && value =~ /^([A-Z]+)$/
|
|
568
|
+
POSITION_ATTRIBUTES["horizontal_position"]["dictionary"][value]
|
|
569
|
+
else
|
|
570
|
+
"posx#{RRTF::Utilities.value2twips(value)}"
|
|
571
|
+
end
|
|
572
|
+
end,
|
|
573
|
+
"to_rtf" => lambda{ |value, document| "\\#{value}" unless value.nil? }
|
|
574
|
+
},
|
|
575
|
+
"vertical_position" => {
|
|
576
|
+
"default" => nil,
|
|
577
|
+
"dictionary" => {
|
|
578
|
+
"CENTER" => "posyc",
|
|
579
|
+
"TOP" => "posyt",
|
|
580
|
+
"BOTTOM" => "posyb"
|
|
581
|
+
},
|
|
582
|
+
"from_user" => lambda do |value|
|
|
583
|
+
return nil if value.nil?
|
|
584
|
+
if value.is_a?(String) && value =~ /^([A-Z]+)$/
|
|
585
|
+
POSITION_ATTRIBUTES["vertical_position"]["dictionary"][value]
|
|
586
|
+
else
|
|
587
|
+
"posy#{RRTF::Utilities.value2twips(value)}"
|
|
588
|
+
end
|
|
589
|
+
end,
|
|
590
|
+
"to_rtf" => lambda{ |value, document| "\\#{value}" unless value.nil? }
|
|
591
|
+
},
|
|
592
|
+
"text_wrap" => {
|
|
593
|
+
"default" => nil,
|
|
594
|
+
"dictionary" => {
|
|
595
|
+
"NONE" => "nowrap",
|
|
596
|
+
"DEFAULT" => "wrapdefault",
|
|
597
|
+
"AROUND" => "wraparound",
|
|
598
|
+
"TIGHT" => "wraptight",
|
|
599
|
+
"THROUGH" => "wrapthrough"
|
|
600
|
+
},
|
|
601
|
+
"to_rtf" => lambda{ |value, document| "\\#{value}" unless value.nil? }
|
|
602
|
+
},
|
|
603
|
+
"drop_cap_lines" => {
|
|
604
|
+
"default" => nil,
|
|
605
|
+
"to_rtf" => lambda{ |value, document| "\\dropcapli#{value}" unless value.nil? }
|
|
606
|
+
},
|
|
607
|
+
"drop_cap_type" => {
|
|
608
|
+
"default" => nil,
|
|
609
|
+
"dictionary" => {
|
|
610
|
+
"IN_TEXT" => 1,
|
|
611
|
+
"IN_MARGIN" => 2
|
|
612
|
+
},
|
|
613
|
+
"to_rtf" => lambda{ |value, document| "\\dropcapt#{value}" unless value.nil? }
|
|
614
|
+
},
|
|
615
|
+
"lock_anchor" => {
|
|
616
|
+
"default" => nil,
|
|
617
|
+
"to_rtf" => lambda{ |value, document| (value ? "\\abslock0" : "\\abslock1") unless value.nil? }
|
|
618
|
+
}
|
|
619
|
+
}.freeze
|
|
620
|
+
|
|
621
|
+
# Generates attribute accessors for all position attributes when the module
|
|
622
|
+
# is included in another module or class.
|
|
623
|
+
def self.included(base)
|
|
624
|
+
# define accessors in base for position attributes
|
|
625
|
+
base.class_eval do
|
|
626
|
+
POSITION_ATTRIBUTES.each do |key, options|
|
|
627
|
+
attr_accessor :"#{key}"
|
|
628
|
+
end # each
|
|
629
|
+
end # class_eval
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
# Initializes position formatting attributes.
|
|
633
|
+
#
|
|
634
|
+
# @param [Hash] options the border formatting options.
|
|
635
|
+
# @option options [String] "sides" ('ALL') the sides to which the border applied ("ALL", "LEFT", "RIGHT", "TOP", or "BOTTOM").
|
|
636
|
+
def initialize_position_formatting(options = {})
|
|
637
|
+
# load default attribute values
|
|
638
|
+
POSITION_ATTRIBUTES.each do |key, options|
|
|
639
|
+
send("#{key}=", options["default"])
|
|
640
|
+
end # each
|
|
641
|
+
# overwrite default attribute values with given values
|
|
642
|
+
set_position_formatting_from_hashmap(options)
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
# Sets formatting attributes according to the supplied hashmap.
|
|
646
|
+
# @see #initialize_position_formatting
|
|
647
|
+
def set_position_formatting_from_hashmap(hash)
|
|
648
|
+
hash.each do |attribute, value|
|
|
649
|
+
# skip unreconized attributes
|
|
650
|
+
next unless(POSITION_ATTRIBUTES.keys.include?(attribute))
|
|
651
|
+
# preprocess value if nessesary
|
|
652
|
+
if POSITION_ATTRIBUTES[attribute].has_key?("from_user")
|
|
653
|
+
value = POSITION_ATTRIBUTES[attribute]["from_user"].call(value)
|
|
654
|
+
elsif POSITION_ATTRIBUTES[attribute].has_key?("dictionary") && value.is_a?(String)
|
|
655
|
+
value = POSITION_ATTRIBUTES[attribute]["dictionary"][value]
|
|
656
|
+
end # if
|
|
657
|
+
# set attribute value
|
|
658
|
+
send("#{attribute}=", value)
|
|
659
|
+
end # each
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
# Generates an RTF string representing all applied position formatting.
|
|
663
|
+
# @note To generate correct RTF control words for colours and fonts, a
|
|
664
|
+
# document object must be provided to this method so that colour and font
|
|
665
|
+
# indicies may be found in the document's colour and font tables, respectively.
|
|
666
|
+
#
|
|
667
|
+
# @param [Document] document the document for which the RTF is to be generated.
|
|
668
|
+
def position_formatting_to_rtf(document)
|
|
669
|
+
text = StringIO.new
|
|
670
|
+
|
|
671
|
+
# accumulate RTF representations of paragraph attributes
|
|
672
|
+
POSITION_ATTRIBUTES.each do |key, options|
|
|
673
|
+
if options.has_key?("to_rtf")
|
|
674
|
+
rtf = options["to_rtf"].call(send(key), document)
|
|
675
|
+
text << rtf unless rtf.nil?
|
|
676
|
+
end # if
|
|
677
|
+
end # each
|
|
678
|
+
|
|
679
|
+
text.string
|
|
680
|
+
end
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
# Paragraph shading formatting attributes and methods.
|
|
684
|
+
# @author Wesley Hileman
|
|
685
|
+
# @since 1.0.0
|
|
686
|
+
module RRTF::ShadingFormatting
|
|
687
|
+
# Formatting attributes that can be applied to shade the background
|
|
688
|
+
# of paragraphs.
|
|
689
|
+
SHADING_ATTRIBUTES = {
|
|
690
|
+
"opacity" => {
|
|
691
|
+
"default" => 100,
|
|
692
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2hunpercent(value) },
|
|
693
|
+
"to_rtf" => lambda{ |value, document| "\\shading#{value}" unless value.nil? }
|
|
694
|
+
},
|
|
695
|
+
"foreground_color" => {
|
|
696
|
+
"default" => nil,
|
|
697
|
+
"from_user" => lambda{ |value| value.is_a?(RRTF::Colour) ? value : RRTF::Colour.from_string(value) },
|
|
698
|
+
"to_rtf" => lambda{ |value, document| "\\cfpat#{document.colours.index(value)}" unless value.nil? }
|
|
699
|
+
},
|
|
700
|
+
"background_color" => {
|
|
701
|
+
"default" => nil,
|
|
702
|
+
"from_user" => lambda{ |value| value.is_a?(RRTF::Colour) ? value : RRTF::Colour.from_string(value) },
|
|
703
|
+
"to_rtf" => lambda{ |value, document| "\\cbpat#{document.colours.index(value)}" unless value.nil? }
|
|
704
|
+
}
|
|
705
|
+
}.freeze
|
|
706
|
+
|
|
707
|
+
# Generates attribute accessors for all position attributes when the module
|
|
708
|
+
# is included in another module or class.
|
|
709
|
+
def self.included(base)
|
|
710
|
+
# define accessors in base for position attributes
|
|
711
|
+
base.class_eval do
|
|
712
|
+
SHADING_ATTRIBUTES.each do |key, options|
|
|
713
|
+
attr_accessor :"#{key}"
|
|
714
|
+
end # each
|
|
715
|
+
end # class_eval
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
# Initializes position formatting attributes.
|
|
719
|
+
#
|
|
720
|
+
# @param [Hash] options the border formatting options.
|
|
721
|
+
# @option options [String] "sides" ('ALL') the sides to which the border applied ("ALL", "LEFT", "RIGHT", "TOP", or "BOTTOM").
|
|
722
|
+
def initialize_shading_formatting(options = {})
|
|
723
|
+
# load default attribute values
|
|
724
|
+
SHADING_ATTRIBUTES.each do |key, options|
|
|
725
|
+
send("#{key}=", options["default"])
|
|
726
|
+
end # each
|
|
727
|
+
# overwrite default attribute values with given values
|
|
728
|
+
set_shading_formatting_from_hashmap(options)
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
# Sets formatting attributes according to the supplied hashmap.
|
|
732
|
+
# @see #initialize_shading_formatting
|
|
733
|
+
def set_shading_formatting_from_hashmap(hash)
|
|
734
|
+
hash.each do |attribute, value|
|
|
735
|
+
# skip unreconized attributes
|
|
736
|
+
next unless(SHADING_ATTRIBUTES.keys.include?(attribute))
|
|
737
|
+
# preprocess value if nessesary
|
|
738
|
+
if SHADING_ATTRIBUTES[attribute].has_key?("from_user")
|
|
739
|
+
value = SHADING_ATTRIBUTES[attribute]["from_user"].call(value)
|
|
740
|
+
elsif SHADING_ATTRIBUTES[attribute].has_key?("dictionary") && value.is_a?(String)
|
|
741
|
+
value = SHADING_ATTRIBUTES[attribute]["dictionary"][value]
|
|
742
|
+
end # if
|
|
743
|
+
# set attribute value
|
|
744
|
+
send("#{attribute}=", value)
|
|
745
|
+
end # each
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
# Generates an RTF string representing all applied position formatting.
|
|
749
|
+
# @note To generate correct RTF control words for colours and fonts, a
|
|
750
|
+
# document object must be provided to this method so that colour and font
|
|
751
|
+
# indicies may be found in the document's colour and font tables, respectively.
|
|
752
|
+
#
|
|
753
|
+
# @param [Document] document the document for which the RTF is to be generated.
|
|
754
|
+
def shading_formatting_to_rtf(document)
|
|
755
|
+
text = StringIO.new
|
|
756
|
+
|
|
757
|
+
# accumulate RTF representations of paragraph attributes
|
|
758
|
+
SHADING_ATTRIBUTES.each do |key, options|
|
|
759
|
+
if options.has_key?("to_rtf")
|
|
760
|
+
rtf = options["to_rtf"].call(send(key), document)
|
|
761
|
+
text << rtf unless rtf.nil?
|
|
762
|
+
end # if
|
|
763
|
+
end # each
|
|
764
|
+
|
|
765
|
+
text.string
|
|
766
|
+
end
|
|
767
|
+
end
|
|
768
|
+
|
|
769
|
+
# Document formatting attributes and methods.
|
|
770
|
+
# @author Wesley Hileman
|
|
771
|
+
# @since 1.0.0
|
|
772
|
+
module RRTF::DocumentFormatting
|
|
773
|
+
# Formatting attributes that can be applied to an RTF document.
|
|
774
|
+
# @return [Hash<String, Hash>] a hash mapping each attribute to a hash that
|
|
775
|
+
# describes (1) the attribute's default value, (2) how to parse the attribute
|
|
776
|
+
# from the user, and (3) how to convert the attribute to an RTF sequence.
|
|
777
|
+
DOCUMENT_ATTRIBUTES = {
|
|
778
|
+
"facing_pages" => {
|
|
779
|
+
"default" => nil,
|
|
780
|
+
"to_rtf" => lambda{ |value| "\\facingp" if value }
|
|
781
|
+
},
|
|
782
|
+
"mirror_margins" => {
|
|
783
|
+
"default" => nil,
|
|
784
|
+
"to_rtf" => lambda{ |value| "\\margmirror" if value }
|
|
785
|
+
},
|
|
786
|
+
"widow_orphan_ctl" => {
|
|
787
|
+
"default" => nil,
|
|
788
|
+
"to_rtf" => lambda{ |value| "\\widowctl" if value }
|
|
789
|
+
},
|
|
790
|
+
"tab_width" => {
|
|
791
|
+
"default" => nil,
|
|
792
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2twips(value) },
|
|
793
|
+
"to_rtf" => lambda{ |value| "\\deftab#{value}" unless value.nil? }
|
|
794
|
+
},
|
|
795
|
+
"hyphenation_width" => {
|
|
796
|
+
"default" => nil,
|
|
797
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2twips(value) },
|
|
798
|
+
"to_rtf" => lambda{ |value| "\\hyphhotz#{value}" unless value.nil? }
|
|
799
|
+
},
|
|
800
|
+
"max_consecutive_hyphenation" => {
|
|
801
|
+
"default" => nil,
|
|
802
|
+
"to_rtf" => lambda{ |value| "\\hyphconsec#{value}" unless value.nil? }
|
|
803
|
+
},
|
|
804
|
+
"hyphenate" => {
|
|
805
|
+
"default" => true,
|
|
806
|
+
"to_rtf" => lambda{ |value| (value ? "\\hyphauto1" : "\\hyphauto0") unless value.nil? }
|
|
807
|
+
}
|
|
808
|
+
}.freeze
|
|
809
|
+
|
|
810
|
+
# Generates attribute accessors for all document attributes when the module
|
|
811
|
+
# is included in another module or class.
|
|
812
|
+
def self.included(base)
|
|
813
|
+
# define accessors in base for document attributes
|
|
814
|
+
base.class_eval do
|
|
815
|
+
DOCUMENT_ATTRIBUTES.each do |key, options|
|
|
816
|
+
attr_accessor :"#{key}"
|
|
817
|
+
end # each
|
|
818
|
+
end # class_eval
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
# Initializes document formatting attributes.
|
|
822
|
+
#
|
|
823
|
+
# @param [Hash] options the document formatting options.
|
|
824
|
+
# @option options [Boolean] "facing_pages" (nil) whether or not to enable facing pages in the document.
|
|
825
|
+
# @option options [Boolean] "mirror_margins" (nil) whether or not to enable mirrored margins (when facing pages is enabled) in the document.
|
|
826
|
+
# @option options [Boolean] "widow_orphan_ctl" (nil) whether or not to enable widow and orphan control for the document.
|
|
827
|
+
# @option options [String] "tab_width" (nil) the default tab width for the document (specify a string, see {Utilities.value2twips}).
|
|
828
|
+
# @option options [String] "hyphenation_width" (nil) the space from the right margin in which hyphenation occurs in the document (specify a string, see {Utilities.value2twips}).
|
|
829
|
+
# @option options [Integer] "max_consecutive_hyphenation" (nil) the maximum number of consecutive hyphentated lines allowed in the document.
|
|
830
|
+
# @option options [Boolean] "hyphenate" (nil) enable or disable hyphenation in the document.
|
|
831
|
+
def initialize_document_formatting(options = {})
|
|
832
|
+
# load default attribute values
|
|
833
|
+
DOCUMENT_ATTRIBUTES.each do |key, options|
|
|
834
|
+
send("#{key}=", options["default"])
|
|
835
|
+
end # each
|
|
836
|
+
# overwrite default attribute values with given values
|
|
837
|
+
set_document_formatting_from_hashmap(options)
|
|
838
|
+
end
|
|
839
|
+
|
|
840
|
+
# Sets document formatting attributes according to the supplied hashmap.
|
|
841
|
+
# @see #initialize_document_formatting
|
|
842
|
+
def set_document_formatting_from_hashmap(hash)
|
|
843
|
+
hash.each do |attribute, value|
|
|
844
|
+
# skip unreconized attributes
|
|
845
|
+
next unless(DOCUMENT_ATTRIBUTES.keys.include?(attribute))
|
|
846
|
+
# preprocess value if nessesary
|
|
847
|
+
if DOCUMENT_ATTRIBUTES[attribute].has_key?("from_user")
|
|
848
|
+
value = DOCUMENT_ATTRIBUTES[attribute]["from_user"].call(value)
|
|
849
|
+
elsif DOCUMENT_ATTRIBUTES[attribute].has_key?("dictionary") && value.is_a?(String)
|
|
850
|
+
value = DOCUMENT_ATTRIBUTES[attribute]["dictionary"][value]
|
|
851
|
+
end # if
|
|
852
|
+
# set attribute value
|
|
853
|
+
send("#{attribute}=", value)
|
|
854
|
+
end # each
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
# Generates an RTF string representing all applied document formatting.
|
|
858
|
+
#
|
|
859
|
+
# @return [String] RTF string.
|
|
860
|
+
def document_formatting_to_rtf
|
|
861
|
+
text = StringIO.new
|
|
862
|
+
|
|
863
|
+
# accumulate RTF representations of document attributes
|
|
864
|
+
DOCUMENT_ATTRIBUTES.each do |key, options|
|
|
865
|
+
if options.has_key?("to_rtf")
|
|
866
|
+
rtf = options["to_rtf"].call(send(key))
|
|
867
|
+
text << rtf unless rtf.nil?
|
|
868
|
+
end # if
|
|
869
|
+
end # each
|
|
870
|
+
|
|
871
|
+
text.string
|
|
872
|
+
end
|
|
873
|
+
end # module DocumentFormatting
|
|
874
|
+
|
|
875
|
+
# Page formatting attributes and methods.
|
|
876
|
+
# @author Wesley Hileman
|
|
877
|
+
# @since 1.0.0
|
|
878
|
+
module RRTF::PageFormatting
|
|
879
|
+
# Formatting attributes that can be applied to an RTF document or a section
|
|
880
|
+
# in a document.
|
|
881
|
+
# @return [Hash<String, Hash>] a hash mapping each attribute to a hash that
|
|
882
|
+
# describes (1) the attribute's default value, (2) how to parse the attribute
|
|
883
|
+
# from the user, and (3) how to convert the attribute to an RTF sequence.
|
|
884
|
+
PAGE_ATTRIBUTES = {
|
|
885
|
+
"orientation" => {
|
|
886
|
+
"default" => :portrait,
|
|
887
|
+
"dictionary" => {
|
|
888
|
+
"PORTRAIT" => :portrait,
|
|
889
|
+
"LANDSCAPE" => :landscape
|
|
890
|
+
},
|
|
891
|
+
"to_rtf" => lambda{ |value| "\\landscape" if value == :landscape }
|
|
892
|
+
},
|
|
893
|
+
"size" => {
|
|
894
|
+
"default" => RRTF::Page::Size.new,
|
|
895
|
+
"from_user" => lambda{ |value| RRTF::Page::Size.new(value) },
|
|
896
|
+
"to_rtf" => lambda{ |value| "\\paperw#{value.width}\\paperh#{value.height}" }
|
|
897
|
+
},
|
|
898
|
+
"margin" => {
|
|
899
|
+
"default" => RRTF::Page::Margin.new,
|
|
900
|
+
"from_user" => lambda{ |value| RRTF::Page::Margin.new(value) },
|
|
901
|
+
"to_rtf" => lambda{ |value| "\\margl#{value.left}\\margr#{value.right}\\margt#{value.top}\\margb#{value.bottom}" }
|
|
902
|
+
},
|
|
903
|
+
"gutter" => {
|
|
904
|
+
"default" => nil,
|
|
905
|
+
"from_user" => lambda{ |value| RRTF::Utilities.value2twips(value) },
|
|
906
|
+
"to_rtf" => lambda{ |value| "\\gutter#{value}" unless value.nil? }
|
|
907
|
+
}
|
|
908
|
+
}.freeze
|
|
909
|
+
|
|
910
|
+
# Generates attribute accessors for all page attributes when the module
|
|
911
|
+
# is included in another module or class.
|
|
912
|
+
def self.included(base)
|
|
913
|
+
# define accessors in base for document attributes
|
|
914
|
+
base.class_eval do
|
|
915
|
+
PAGE_ATTRIBUTES.each do |key, options|
|
|
916
|
+
attr_accessor :"#{key}"
|
|
917
|
+
end # each
|
|
918
|
+
end # class_eval
|
|
919
|
+
end
|
|
920
|
+
|
|
921
|
+
# Initializes page formatting attributes.
|
|
922
|
+
# @note The behavior of the "gutter" option changes with the document
|
|
923
|
+
# "facing_pages" setting.
|
|
924
|
+
#
|
|
925
|
+
# @param [Hash] options the document formatting options.
|
|
926
|
+
# @option options [String] "orientation" ("PORTRAIT") the orientation of the paper ("PORTRAIT" or "LANDSCAPE").
|
|
927
|
+
# @option options [String, Page::Size] "size" (Page::Size.new) the size of the paper (object or string; see {Page::Size#initialize}).
|
|
928
|
+
# @option options [String, Page::Margin] "margin" (Page::Margin.new) the paper margin (object or string; see {Page::Margin#initialize}).
|
|
929
|
+
# @option options [String] "gutter" (nil) the page gutter width (specify a string, see {Utilities.value2twips}).
|
|
930
|
+
def initialize_page_formatting(options = {})
|
|
931
|
+
# load default attribute values
|
|
932
|
+
PAGE_ATTRIBUTES.each do |key, options|
|
|
933
|
+
send("#{key}=", options["default"])
|
|
934
|
+
end # each
|
|
935
|
+
# overwrite default attribute values with given values
|
|
936
|
+
set_page_formatting_from_hashmap(options)
|
|
937
|
+
end
|
|
938
|
+
|
|
939
|
+
# Sets document formatting attributes according to the supplied hashmap.
|
|
940
|
+
# @see #initialize_page_formatting
|
|
941
|
+
def set_page_formatting_from_hashmap(hash)
|
|
942
|
+
hash.each do |attribute, value|
|
|
943
|
+
# skip unreconized attributes
|
|
944
|
+
next unless(PAGE_ATTRIBUTES.keys.include?(attribute))
|
|
945
|
+
# preprocess value if nessesary
|
|
946
|
+
if PAGE_ATTRIBUTES[attribute].has_key?("from_user")
|
|
947
|
+
value = PAGE_ATTRIBUTES[attribute]["from_user"].call(value)
|
|
948
|
+
elsif PAGE_ATTRIBUTES[attribute].has_key?("dictionary") && value.is_a?(String)
|
|
949
|
+
value = PAGE_ATTRIBUTES[attribute]["dictionary"][value]
|
|
950
|
+
end # if
|
|
951
|
+
# set attribute value
|
|
952
|
+
send("#{attribute}=", value)
|
|
953
|
+
end # each
|
|
954
|
+
end
|
|
955
|
+
|
|
956
|
+
# Generates an RTF string representing all applied page formatting.
|
|
957
|
+
#
|
|
958
|
+
# @return [String] RTF string.
|
|
959
|
+
def page_formatting_to_rtf
|
|
960
|
+
text = StringIO.new
|
|
961
|
+
|
|
962
|
+
# accumulate RTF representations of page attributes
|
|
963
|
+
PAGE_ATTRIBUTES.each do |key, options|
|
|
964
|
+
if options.has_key?("to_rtf")
|
|
965
|
+
rtf = options["to_rtf"].call(send(key))
|
|
966
|
+
text << rtf unless rtf.nil?
|
|
967
|
+
end # if
|
|
968
|
+
end # each
|
|
969
|
+
|
|
970
|
+
text.string
|
|
971
|
+
end
|
|
972
|
+
|
|
973
|
+
def body_width
|
|
974
|
+
if orientation == :portrait
|
|
975
|
+
size.width - (margin.left + margin.right)
|
|
976
|
+
else
|
|
977
|
+
size.height - (margin.top + margin.bottom)
|
|
978
|
+
end
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
def body_height
|
|
982
|
+
if orientation == :portrait
|
|
983
|
+
size.height - (margin.top + margin.bottom)
|
|
984
|
+
else
|
|
985
|
+
size.width - (margin.left + margin.right)
|
|
986
|
+
end
|
|
987
|
+
end
|
|
988
|
+
end
|