]> Shamusworld >> Repos - architektonas/blob - src/base/rs_font.cpp
b8a3e6cc1c19b8b7621db9bdbc6061016b39139f
[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 file(path);
123
124         if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
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(&file);
136         QString line;
137
138         // Read line by line until we find a new letter:
139 //I think this is wrong... We're mixing classes here...
140 //AND THAT WAS THE PROBLEM!!!
141 //      while (!file.atEnd())
142         while (!ts.atEnd())
143         {
144                 line = ts.readLine();
145 //printf("\"%s\"\n", line.toAscii().data());
146                 if (line.isEmpty())
147                         continue;
148
149                 // Read font settings:
150                 if (line.at(0) == '#')
151                 {
152 #if 0
153 //                      QStringList lst = QStringList::split(':', line.right(line.length() - 1));
154                         QStringList lst = line.right(line.length() - 1).split(":");
155                         QStringList::Iterator it3 = lst.begin();
156
157 //                      QString identifier = (*it3).stripWhiteSpace();
158                         QString identifier = (*it3);
159                         identifier = identifier.simplified().toLower();
160                         it3++;
161 //                      QString value = (*it3).stripWhiteSpace();
162                         QString value = (*it3);
163                         value = value.simplified().toLower();
164 #else
165                         QStringList list = line.right(line.length() - 1).split(":");
166                         QString identifier = "", value = "";
167
168                         if (list.size() >= 1)
169                                 identifier = list[0].simplified().toLower();
170
171                         if (list.size() >= 2)
172                                 value = list[1].simplified();//.toLower();
173 #endif
174 //printf("--> identifier=\"%s\", value=\"%s\"\n", identifier.toAscii().data(), value.toAscii().data());
175
176                         if (identifier == "letterspacing")
177                                 letterSpacing = value.toDouble();
178                         else if (identifier == "wordspacing")
179                                 wordSpacing = value.toDouble();
180                         else if (identifier == "linespacingfactor")
181                                 lineSpacingFactor = value.toDouble();
182                         else if (identifier == "author")
183                                 authors.append(value);
184                         else if (identifier == "name")
185                                 names.append(value);
186                         else if (identifier == "encoding")
187                         {
188                                 ts.setCodec(QTextCodec::codecForName(value.toAscii()));
189                                 encoding = value;
190                         }
191                 }
192                 // Add another letter to this font:
193                 else if (line.at(0) == '[')
194                 {
195                         // uniode character:
196                         QChar ch;
197
198                         // read unicode:
199                         QRegExp regexp("[0-9A-Fa-f]{4,4}");
200 //                      regexp.search(line);
201                         regexp.indexIn(line);
202                         QString cap = regexp.cap();
203
204                         if (!cap.isNull())
205                         {
206                                 int uCode = cap.toInt(NULL, 16);
207                                 ch = QChar(uCode);
208                         }
209                         // read UTF8 (qcad 1 compatibility)
210 //                      else if (line.find(']') >= 3)
211                         else if (line.indexOf(']') >= 3)
212                         {
213 //                              int i = line.find(']');
214                                 int i = line.indexOf(']');
215                                 QString mid = line.mid(1, i - 1);
216                                 ch = QString::fromUtf8(mid.toLatin1()).at(0);
217                         }
218                         // read normal ascii character:
219                         else
220                         {
221                                 ch = line.at(1);
222                         }
223
224                         // create new letter:
225                         RS_FontChar * letter = new RS_FontChar(NULL, ch, Vector(0.0, 0.0));
226
227                         // Read entities of this letter:
228                         line = ts.readLine();
229
230                         while (!line.isEmpty())
231                         {
232                                 QString coordsStr = line.right(line.length() - 2);
233                                 QStringList coords = coordsStr.split(",");
234                                 QStringList::Iterator it2 = coords.begin();
235
236                                 // Line:
237                                 if (line.at(0) == 'L')
238                                 {
239                                         double x1 = (*it2++).toDouble();
240                                         double y1 = (*it2++).toDouble();
241                                         double x2 = (*it2++).toDouble();
242                                         double y2 = (*it2).toDouble();
243
244                                         RS_LineData ld(Vector(x1, y1), Vector(x2, y2));
245                                         RS_Line * line = new RS_Line(letter, ld);
246                                         line->setPen(RS_Pen(RS2::FlagInvalid));
247                                         line->setLayer(NULL);
248                                         letter->addEntity(line);
249                                 }
250                                 // Arc:
251                                 else if (line.at(0) == 'A')
252                                 {
253                                         double cx = (*it2++).toDouble();
254                                         double cy = (*it2++).toDouble();
255                                         double r = (*it2++).toDouble();
256                                         double a1 = (*it2++).toDouble() / ARAD;
257                                         double a2 = (*it2).toDouble() / ARAD;
258                                         bool reversed = (line.at(1) == 'R');
259
260                                         RS_ArcData ad(Vector(cx, cy), r, a1, a2, reversed);
261                                         RS_Arc * arc = new RS_Arc(letter, ad);
262                                         arc->setPen(RS_Pen(RS2::FlagInvalid));
263                                         arc->setLayer(NULL);
264                                         letter->addEntity(arc);
265                                 }
266
267                                 line = ts.readLine();
268                         }
269
270                         letter->calculateBorders();
271                         letterList.add(letter);
272                 }
273         }
274
275         file.close();
276         loaded = true;
277
278         RS_DEBUG->print("RS_Font::loadFont OK");
279
280         return true;
281 }
282
283 // Wrappers for block list (letters) functions
284 RS_BlockList * RS_Font::getLetterList()
285 {
286         return &letterList;
287 }
288
289 RS_Block * RS_Font::findLetter(const QString & name)
290 {
291         return letterList.find(name);
292 }
293
294 uint RS_Font::countLetters()
295 {
296         return letterList.count();
297 }
298
299 RS_Block * RS_Font::letterAt(uint i)
300 {
301         return letterList.at(i);
302 }
303
304 /**
305  * Dumps the fonts data to stdout.
306  */
307 std::ostream & operator<<(std::ostream & os, const RS_Font & f)
308 {
309     os << " Font file name: " << f.getFileName().toLatin1().data() << "\n";
310     //<< (RS_BlockList&)f << "\n";
311     return os;
312 }