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