diff options
author | fluxgen <fluxgen> | 2004-08-10 18:08:37 (GMT) |
---|---|---|
committer | fluxgen <fluxgen> | 2004-08-10 18:08:37 (GMT) |
commit | c1b226b7ff828a8190508aafb2735ce0f73d10e7 (patch) | |
tree | 9be28fd30ccf817eda02ed97f651a9820ec7a21b /src/FbTk/Font.cc | |
parent | 12237ed0db778fecc92e699fd2a190a0c1b3ac79 (diff) | |
download | fluxbox-c1b226b7ff828a8190508aafb2735ce0f73d10e7.zip fluxbox-c1b226b7ff828a8190508aafb2735ce0f73d10e7.tar.bz2 |
adding halo and shadow options to font loading, patch from Mathias Gumz and c. mccreesh (ciaranm)
Diffstat (limited to 'src/FbTk/Font.cc')
-rw-r--r-- | src/FbTk/Font.cc | 185 |
1 files changed, 144 insertions, 41 deletions
diff --git a/src/FbTk/Font.cc b/src/FbTk/Font.cc index 75d89f1..709c8e4 100644 --- a/src/FbTk/Font.cc +++ b/src/FbTk/Font.cc | |||
@@ -19,9 +19,10 @@ | |||
19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 19 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
20 | // DEALINGS IN THE SOFTWARE. | 20 | // DEALINGS IN THE SOFTWARE. |
21 | 21 | ||
22 | //$Id: Font.cc,v 1.8 2004/08/10 11:21:50 fluxgen Exp $ | 22 | //$Id: Font.cc,v 1.9 2004/08/10 18:08:37 fluxgen Exp $ |
23 | 23 | ||
24 | 24 | ||
25 | #include "StringUtil.hh" | ||
25 | #include "Font.hh" | 26 | #include "Font.hh" |
26 | #include "FontImp.hh" | 27 | #include "FontImp.hh" |
27 | #include "I18n.hh" | 28 | #include "I18n.hh" |
@@ -56,12 +57,27 @@ | |||
56 | #include <iostream> | 57 | #include <iostream> |
57 | #include <cstring> | 58 | #include <cstring> |
58 | #include <cstdlib> | 59 | #include <cstdlib> |
60 | #include <list> | ||
59 | #include <typeinfo> | 61 | #include <typeinfo> |
60 | 62 | ||
63 | |||
64 | #ifdef HAVE_SSTREAM | ||
65 | #include <sstream> | ||
66 | #define FB_istringstream istringstream | ||
67 | #elif HAVE_STRSTREAM | ||
68 | #include <strstream> | ||
69 | #define FB_istringstream istrstream | ||
70 | #else | ||
71 | #error "You dont have sstream or strstream headers!" | ||
72 | #endif // HAVE_STRSTREAM | ||
73 | |||
61 | #include <cstdlib> | 74 | #include <cstdlib> |
62 | 75 | ||
63 | using namespace std; | 76 | using namespace std; |
64 | 77 | ||
78 | |||
79 | namespace { | ||
80 | |||
65 | #ifdef HAVE_SETLOCALE | 81 | #ifdef HAVE_SETLOCALE |
66 | #include <locale.h> | 82 | #include <locale.h> |
67 | #endif //HAVE_SETLOCALE | 83 | #endif //HAVE_SETLOCALE |
@@ -74,7 +90,7 @@ using namespace std; | |||
74 | @param len number of chars to convert | 90 | @param len number of chars to convert |
75 | @return the recoded string, or 0 on failure | 91 | @return the recoded string, or 0 on failure |
76 | */ | 92 | */ |
77 | static char* recode(iconv_t cd, | 93 | char* recode(iconv_t cd, |
78 | const char *msg, size_t size) { | 94 | const char *msg, size_t size) { |
79 | 95 | ||
80 | // If empty message, yes this can happen, return | 96 | // If empty message, yes this can happen, return |
@@ -110,6 +126,75 @@ static char* recode(iconv_t cd, | |||
110 | return new_msg; | 126 | return new_msg; |
111 | } | 127 | } |
112 | 128 | ||
129 | |||
130 | int extract_halo_options(const std::string& opts, std::string& color) { | ||
131 | std::list< std::string > tokens; | ||
132 | size_t sep= opts.find_first_of(':'); | ||
133 | |||
134 | if ( sep == std::string::npos ) | ||
135 | return 1; | ||
136 | |||
137 | FbTk::StringUtil::stringtok(tokens, opts.substr(sep + 1, opts.length()), ";"); | ||
138 | tokens.unique(); | ||
139 | std::list< std::string >::const_iterator token; | ||
140 | |||
141 | for ( token= tokens.begin(); token != tokens.end(); token++ ) { | ||
142 | if ( (*token).find("color=", 0) != std::string::npos ) { | ||
143 | size_t s= (*token).find_first_of('='); | ||
144 | std::string c= (*token).substr(s + 1, (*token).length()); | ||
145 | if ( !c.empty() ) | ||
146 | std::swap(color, c); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | return 1; | ||
151 | } | ||
152 | |||
153 | int extract_shadow_options(const std::string& opts, | ||
154 | std::string& color, | ||
155 | int& offx, int& offy) { | ||
156 | |||
157 | std::list< std::string > tokens; | ||
158 | size_t sep= opts.find_first_of(':'); | ||
159 | |||
160 | if ( sep == std::string::npos ) | ||
161 | return 1; | ||
162 | |||
163 | FbTk::StringUtil::stringtok(tokens, opts.substr(sep + 1, opts.length()), ";"); | ||
164 | tokens.unique(); | ||
165 | std::list< std::string >::const_iterator token; | ||
166 | |||
167 | for ( token= tokens.begin(); token != tokens.end(); token++ ) { | ||
168 | if ( (*token).find("color=", 0) != std::string::npos ) { | ||
169 | size_t s= (*token).find_first_of('='); | ||
170 | std::string c= (*token).substr(s + 1, (*token).length()); | ||
171 | if ( !c.empty() ) | ||
172 | std::swap(color, c); | ||
173 | } | ||
174 | else if ( (*token).find("offsetx=", 0) != std::string::npos ) { | ||
175 | size_t s= (*token).find_first_of('='); | ||
176 | FB_istringstream o((*token).substr(s + 1, (*token).length())); | ||
177 | if ( !o.eof() ) { | ||
178 | o >> offx; | ||
179 | } | ||
180 | } | ||
181 | else if ( (*token).find("offsety=", 0) != std::string::npos ) { | ||
182 | size_t s= (*token).find_first_of('='); | ||
183 | FB_istringstream o((*token).substr(s + 1, (*token).length())); | ||
184 | if ( !o.eof() ) { | ||
185 | o >> offy; | ||
186 | } | ||
187 | } | ||
188 | } | ||
189 | |||
190 | return 1; | ||
191 | |||
192 | }; | ||
193 | |||
194 | }; // end nameless namespace | ||
195 | |||
196 | |||
197 | |||
113 | namespace FbTk { | 198 | namespace FbTk { |
114 | 199 | ||
115 | bool Font::m_multibyte = false; | 200 | bool Font::m_multibyte = false; |
@@ -117,7 +202,10 @@ bool Font::m_utf8mode = false; | |||
117 | 202 | ||
118 | Font::Font(const char *name, bool antialias): | 203 | Font::Font(const char *name, bool antialias): |
119 | m_fontimp(0), | 204 | m_fontimp(0), |
120 | m_antialias(false), m_rotated(false), m_shadow(false), | 205 | m_antialias(false), m_rotated(false), |
206 | m_shadow(false), m_shadow_color("#000000"), | ||
207 | m_shadow_offx(1), m_shadow_offy(1), | ||
208 | m_halo(false), m_halo_color("#ffffff"), | ||
121 | m_iconv((iconv_t)-1) { | 209 | m_iconv((iconv_t)-1) { |
122 | 210 | ||
123 | // MB_CUR_MAX returns the size of a char in the current locale | 211 | // MB_CUR_MAX returns the size of a char in the current locale |
@@ -222,46 +310,49 @@ void Font::setAntialias(bool flag) { | |||
222 | bool Font::load(const std::string &name) { | 310 | bool Font::load(const std::string &name) { |
223 | if (name.size() == 0) | 311 | if (name.size() == 0) |
224 | return false; | 312 | return false; |
225 | // copy name so we can manipulate it | ||
226 | std::string new_name = name; | ||
227 | 313 | ||
228 | m_shadow = false; | 314 | m_shadow = false; |
229 | 315 | m_halo = false; | |
230 | // find font option "shadow" | 316 | |
231 | size_t start_pos = new_name.find_first_of(':'); | 317 | // everything after ':' is a fontoption |
232 | if (start_pos != std::string::npos) { | 318 | // -> extract 'halo' and 'shadow' and |
233 | size_t shadow_pos = new_name.find("shadow", start_pos); | 319 | // load remaining fname |
234 | if (shadow_pos != std::string::npos) { | 320 | std::list< std::string > tokens; |
235 | m_shadow = true; | 321 | size_t sep= name.find_first_of(':'); |
236 | // erase "shadow" since it's not a valid option for the font | 322 | std::string fname; |
237 | new_name.erase(shadow_pos, 6); | 323 | |
238 | 324 | if ( sep != std::string::npos ) { | |
239 | // is the option row empty? | 325 | fname= std::string(name.c_str(), sep + 1); |
240 | if (new_name.find_first_not_of("\t ,", start_pos + 1) == std::string::npos) | 326 | FbTk::StringUtil::stringtok(tokens, name.substr(sep + 1, name.length()), ","); |
241 | new_name.erase(start_pos); // erase the ':' and the rest of the line | ||
242 | else { | ||
243 | // there might be some options left so we need to remove the "," | ||
244 | // before/after "shadow" option | ||
245 | size_t pos = new_name.find_last_not_of("\t ", shadow_pos); | ||
246 | if (pos != std::string::npos) { | ||
247 | if (new_name[pos] == ',') | ||
248 | new_name.erase(pos, 1); | ||
249 | |||
250 | } | 327 | } |
251 | 328 | else | |
252 | // ok, we removed the "," and "shadow" now we need to determine | 329 | fname= name; |
253 | // if we need to remove the ":" , so we search for anything except | 330 | |
254 | // \t and space and if we dont find anything the ":" is removed | 331 | tokens.unique(); |
255 | if (new_name.find_first_not_of("\t ", start_pos + 1) == std::string::npos) | 332 | bool firstone= true; |
256 | new_name.erase(start_pos, 1); | 333 | std::list< std::string >::const_iterator token; |
257 | 334 | ||
335 | // check tokens and extract extraoptions for halo and shadow | ||
336 | for( token= tokens.begin(); token != tokens.end(); token++ ) { | ||
337 | if ( (*token).find("halo",0) != std::string::npos ) { | ||
338 | m_halo= true; | ||
339 | extract_halo_options(*token, m_halo_color); | ||
340 | } | ||
341 | else if ( (*token).find("shadow", 0) != std::string::npos ) { | ||
342 | m_shadow= true; | ||
343 | extract_shadow_options(*token, m_shadow_color, m_shadow_offx, m_shadow_offy); | ||
258 | } | 344 | } |
259 | 345 | else { | |
346 | if ( !firstone ) | ||
347 | fname+= ", "; | ||
348 | else | ||
349 | firstone= false; | ||
350 | fname= fname + *token; | ||
260 | } | 351 | } |
261 | } | 352 | } |
262 | 353 | ||
263 | m_fontstr = name; | 354 | m_fontstr = fname; |
264 | return m_fontimp->load(new_name.c_str()); | 355 | return m_fontimp->load(fname.c_str()); |
265 | } | 356 | } |
266 | 357 | ||
267 | unsigned int Font::textWidth(const char * const text, unsigned int size) const { | 358 | unsigned int Font::textWidth(const char * const text, unsigned int size) const { |
@@ -312,13 +403,25 @@ void Font::drawText(Drawable w, int screen, GC gc, | |||
312 | 403 | ||
313 | const char *real_text = rtext ? rtext : text; | 404 | const char *real_text = rtext ? rtext : text; |
314 | 405 | ||
315 | // draw shadow first | 406 | // draw "effects" first |
316 | if (first_run && m_shadow) { | 407 | if (first_run) { |
408 | if (m_shadow) { | ||
317 | FbTk::GContext shadow_gc(w); | 409 | FbTk::GContext shadow_gc(w); |
318 | shadow_gc.setForeground(FbTk::Color("black", screen)); | 410 | shadow_gc.setForeground(FbTk::Color(m_shadow_color.c_str(), screen)); |
319 | first_run = false; // so we don't end up in a loop | 411 | first_run = false; |
320 | drawText(w, screen, shadow_gc.gc(), real_text, len, x + 1, y + 1); | 412 | drawText(w, screen, shadow_gc.gc(), real_text, len, |
413 | x + m_shadow_offx, y + m_shadow_offy, rotate); | ||
321 | first_run = true; | 414 | first_run = true; |
415 | } else if (m_halo) { | ||
416 | FbTk::GContext halo_gc(w); | ||
417 | halo_gc.setForeground(FbTk::Color(m_halo_color.c_str(), screen)); | ||
418 | first_run = false; | ||
419 | drawText(w, screen, halo_gc.gc(), real_text, len, x + 1, y + 1, rotate); | ||
420 | drawText(w, screen, halo_gc.gc(), real_text, len, x - 1, y + 1, rotate); | ||
421 | drawText(w, screen, halo_gc.gc(), real_text, len, x - 1, y - 1, rotate); | ||
422 | drawText(w, screen, halo_gc.gc(), real_text, len, x + 1, y - 1, rotate); | ||
423 | first_run = true; | ||
424 | } | ||
322 | } | 425 | } |
323 | 426 | ||
324 | if (!rotate && isRotated()) { | 427 | if (!rotate && isRotated()) { |