]> Shamusworld >> Repos - architektonas/blob - src/base/rs_font.cpp
Changed RS_Graphic to Drawing; this is less confusing as a drawing is
[architektonas] / src / base / rs_font.cpp
1 // rs_font.cpp
2 //
3 // Part of the Architektonas Project
4 // Originally part of QCad Community Edition by Andrew Mustun
5 // Extensively rewritten and refactored by James L. Hammons
6 // (C) 2010 Underground Software
7 //
8 // JLH = James L. Hammons <jlhamm@acm.org>
9 //
10 // Who  When        What
11 // ---  ----------  -----------------------------------------------------------
12 // JLH  05/28/2010  Added this text. :-)
13 //
14
15 #include "rs_font.h"
16
17 #include "rs_color.h"
18 #include "rs_fontchar.h"
19 #include "rs_math.h"
20 #include "rs_system.h"
21
22 /**
23  * Constructor.
24  *
25  * @param owner true if the font owns the letters (blocks). Otherwise
26  *              the letters will be deleted when the font is deleted.
27  */
28 RS_Font::RS_Font(const QString & fileName, bool owner): letterList(owner)
29 {
30         this->fileName = fileName;
31         encoding = "";
32         loaded = false;
33         letterSpacing = 3.0;
34         wordSpacing = 6.75;
35         lineSpacingFactor = 1.0;
36 }
37
38 /** @return the fileName of this font. */
39 QString RS_Font::getFileName() const
40 {
41         return fileName;
42 }
43
44 /** @return the encoding of this font. */
45 QString RS_Font::getEncoding() const
46 {
47         return encoding;
48 }
49
50 /** @return the alternative names of this font. */
51 const QStringList & RS_Font::getNames() const
52 {
53         return names;
54 }
55
56 /** @return the author(s) of this font. */
57 const QStringList & RS_Font::getAuthors() const
58 {
59         return authors;
60 }
61
62 /** @return Default letter spacing for this font */
63 double RS_Font::getLetterSpacing()
64 {
65         return letterSpacing;
66 }
67
68 /** @return Default word spacing for this font */
69 double RS_Font::getWordSpacing()
70 {
71         return wordSpacing;
72 }
73
74 /** @return Default line spacing factor for this font */
75 double RS_Font::getLineSpacingFactor()
76 {
77         return lineSpacingFactor;
78 }
79
80 /**
81  * Loads the font into memory.
82  *
83  * @retval true font was already loaded or is loaded now.
84  * @retval false font could not be loaded.
85  */
86 bool RS_Font::loadFont()
87 {
88         RS_DEBUG->print("RS_Font::loadFont");
89
90         if (loaded)
91                 return true;
92
93         QString path;
94
95         // Search for the appropriate font if we have only the name of the font:
96         if (!fileName.toLower().contains(".cxf"))
97         {
98                 QStringList fonts = RS_SYSTEM->getFontList();
99                 QFileInfo file;
100
101                 for(QStringList::Iterator it=fonts.begin(); it!=fonts.end(); it++)
102                 {
103                         if (QFileInfo(*it).baseName().toLower() == fileName.toLower())
104                         {
105                                 path = *it;
106                                 break;
107                         }
108                 }
109         }
110         // We have the full path of the font:
111         else
112                 path = fileName;
113
114         // No font paths found:
115         if (path.isEmpty())
116         {
117                 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Font::loadFont: No fonts available.");
118                 return false;
119         }
120
121         // Open cxf file:
122         QFile f(path);
123
124         if (!f.open(QIODevice::ReadOnly))
125         {
126                 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Font::loadFont: Cannot open font file: %s",
127                         path.toLatin1().data());
128                 return false;
129         }
130         else
131         {
132                 RS_DEBUG->print("RS_Font::loadFont: Successfully opened font file: %s", path.toLatin1().data());
133         }
134
135         QTextStream ts(&f);
136         QString line;
137
138         // Read line by line until we find a new letter:
139         while (!f.atEnd())
140         {
141                 line = ts.readLine();
142
143                 if (line.isEmpty())
144                         continue;
145
146                 // Read font settings:
147                 if (line.at(0) == '#')
148                 {
149 #if 0
150 //                      QStringList lst = QStringList::split(':', line.right(line.length() - 1));
151                         QStringList lst = line.right(line.length() - 1).split(":");
152                         QStringList::Iterator it3 = lst.begin();
153
154 //                      QString identifier = (*it3).stripWhiteSpace();
155                         QString identifier = (*it3);
156                         identifier = identifier.simplified().toLower();
157                         it3++;
158 //                      QString value = (*it3).stripWhiteSpace();
159                         QString value = (*it3);
160                         value = value.simplified().toLower();
161 #else
162                         QStringList list = line.right(line.length() - 1).split(":");
163                         QString identifier = "", value = "";
164
165                         if (list.size() >= 1)
166                                 identifier = list[0].simplified().toLower();
167
168                         if (list.size() >= 2)
169                                 value = list[1].simplified();//.toLower();
170 #endif
171
172                         if (identifier == "letterspacing")
173                                 letterSpacing = value.toDouble();
174                         else if (identifier == "wordspacing")
175                                 wordSpacing = value.toDouble();
176                         else if (identifier == "linespacingfactor")
177                                 lineSpacingFactor = value.toDouble();
178                         else if (identifier == "author")
179                                 authors.append(value);
180                         else if (identifier == "name")
181                                 names.append(value);
182                         else if (identifier == "encoding")
183                         {
184                                 ts.setCodec(QTextCodec::codecForName(value.toAscii()));
185                                 encoding = value;
186                         }
187                 }
188                 // Add another letter to this font:
189                 else if (line.at(0) == '[')
190                 {
191                         // uniode character:
192                         QChar ch;
193
194                         // read unicode:
195                         QRegExp regexp("[0-9A-Fa-f]{4,4}");
196 //                      regexp.search(line);
197                         regexp.indexIn(line);
198                         QString cap = regexp.cap();
199
200                         if (!cap.isNull())
201                         {
202                                 int uCode = cap.toInt(NULL, 16);
203                                 ch = QChar(uCode);
204                         }
205                         // read UTF8 (qcad 1 compatibility)
206 //                      else if (line.find(']') >= 3)
207                         else if (line.indexOf(']') >= 3)
208                         {
209 //                              int i = line.find(']');
210                                 int i = line.indexOf(']');
211                                 QString mid = line.mid(1, i - 1);
212                                 ch = QString::fromUtf8(mid.toLatin1()).at(0);
213                         }
214                         // read normal ascii character:
215                         else
216                         {
217                                 ch = line.at(1);
218                         }
219
220                         // create new letter:
221                         RS_FontChar * letter = new RS_FontChar(NULL, ch, Vector(0.0, 0.0));
222
223                         // Read entities of this letter:
224                         line = ts.readLine();
225
226                         while (!line.isEmpty())
227                         {
228                                 QString coordsStr = line.right(line.length() - 2);
229                                 QStringList coords = coordsStr.split(",");
230                                 QStringList::Iterator it2 = coords.begin();
231
232                                 // Line:
233                                 if (line.at(0) == 'L')
234                                 {
235                                         double x1 = (*it2++).toDouble();
236                                         double y1 = (*it2++).toDouble();
237                                         double x2 = (*it2++).toDouble();
238                                         double y2 = (*it2).toDouble();
239
240                                         RS_LineData ld(Vector(x1, y1), Vector(x2, y2));
241                                         RS_Line * line = new RS_Line(letter, ld);
242                                         line->setPen(RS_Pen(RS2::FlagInvalid));
243                                         line->setLayer(NULL);
244                                         letter->addEntity(line);
245                                 }
246                                 // Arc:
247                                 else if (line.at(0) == 'A')
248                                 {
249                                         double cx = (*it2++).toDouble();
250                                         double cy = (*it2++).toDouble();
251                                         double r = (*it2++).toDouble();
252                                         double a1 = (*it2++).toDouble() / ARAD;
253                                         double a2 = (*it2).toDouble() / ARAD;
254                                         bool reversed = (line.at(1) == 'R');
255
256                                         RS_ArcData ad(Vector(cx, cy), r, a1, a2, reversed);
257                                         RS_Arc * arc = new RS_Arc(letter, ad);
258                                         arc->setPen(RS_Pen(RS2::FlagInvalid));
259                                         arc->setLayer(NULL);
260                                         letter->addEntity(arc);
261                                 }
262
263                                 line = ts.readLine();
264                         }
265
266                         letter->calculateBorders();
267                         letterList.add(letter);
268                 }
269         }
270
271         f.close();
272         loaded = true;
273
274         RS_DEBUG->print("RS_Font::loadFont OK");
275
276         return true;
277 }
278
279 // Wrappers for block list (letters) functions
280 RS_BlockList * RS_Font::getLetterList()
281 {
282         return &letterList;
283 }
284
285 RS_Block * RS_Font::findLetter(const QString & name)
286 {
287         return letterList.find(name);
288 }
289
290 uint RS_Font::countLetters()
291 {
292         return letterList.count();
293 }
294
295 RS_Block * RS_Font::letterAt(uint i)
296 {
297         return letterList.at(i);
298 }
299
300 /**
301  * Dumps the fonts data to stdout.
302  */
303 std::ostream & operator<<(std::ostream & os, const RS_Font & f)
304 {
305     os << " Font file name: " << f.getFileName().toLatin1().data() << "\n";
306     //<< (RS_BlockList&)f << "\n";
307     return os;
308 }