From c1b226b7ff828a8190508aafb2735ce0f73d10e7 Mon Sep 17 00:00:00 2001
From: fluxgen <fluxgen>
Date: Tue, 10 Aug 2004 18:08:37 +0000
Subject: adding halo and shadow options to font loading, patch from Mathias
 Gumz and c. mccreesh (ciaranm)

---
 src/FbTk/Font.cc | 185 +++++++++++++++++++++++++++++++++++++++++++------------
 src/FbTk/Font.hh |  11 +++-
 2 files changed, 153 insertions(+), 43 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 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-//$Id: Font.cc,v 1.8 2004/08/10 11:21:50 fluxgen Exp $
+//$Id: Font.cc,v 1.9 2004/08/10 18:08:37 fluxgen Exp $
 
 
+#include "StringUtil.hh"
 #include "Font.hh"
 #include "FontImp.hh"
 #include "I18n.hh"
@@ -56,12 +57,27 @@
 #include <iostream> 
 #include <cstring>
 #include <cstdlib>
+#include <list>
 #include <typeinfo>
 
+
+#ifdef HAVE_SSTREAM
+#include <sstream>
+#define FB_istringstream istringstream
+#elif HAVE_STRSTREAM
+#include <strstream>
+#define FB_istringstream istrstream
+#else
+#error "You dont have sstream or strstream headers!"
+#endif // HAVE_STRSTREAM
+
 #include <cstdlib>
 
 using namespace std;
 
+
+namespace {
+
 #ifdef HAVE_SETLOCALE
 #include <locale.h>
 #endif //HAVE_SETLOCALE
@@ -74,7 +90,7 @@ using namespace std;
    @param len number of chars to convert
    @return the recoded string, or 0 on failure
 */
-static char* recode(iconv_t cd,
+char* recode(iconv_t cd,
                     const char *msg, size_t size) {
 
     // If empty message, yes this can happen, return
@@ -110,6 +126,75 @@ static char* recode(iconv_t cd,
     return new_msg;
 }
 
+
+int extract_halo_options(const std::string& opts, std::string& color) {
+   std::list< std::string > tokens;
+   size_t sep= opts.find_first_of(':');
+
+   if ( sep == std::string::npos )
+       return 1;
+
+   FbTk::StringUtil::stringtok(tokens, opts.substr(sep + 1, opts.length()), ";");
+   tokens.unique();
+   std::list< std::string >::const_iterator token;
+
+   for ( token= tokens.begin(); token != tokens.end(); token++ ) {
+       if ( (*token).find("color=", 0) != std::string::npos ) {
+           size_t s= (*token).find_first_of('=');
+           std::string c= (*token).substr(s + 1, (*token).length());
+           if ( !c.empty() )
+               std::swap(color, c);
+       }
+   }
+
+   return 1;
+}
+
+int extract_shadow_options(const std::string& opts, 
+                           std::string& color, 
+                           int& offx, int& offy) {
+
+   std::list< std::string > tokens;
+   size_t sep= opts.find_first_of(':');
+
+   if ( sep == std::string::npos )
+       return 1;
+
+   FbTk::StringUtil::stringtok(tokens, opts.substr(sep + 1, opts.length()), ";");
+   tokens.unique();
+   std::list< std::string >::const_iterator token;
+
+   for ( token= tokens.begin(); token != tokens.end(); token++ ) {
+       if ( (*token).find("color=", 0) != std::string::npos ) {
+           size_t s= (*token).find_first_of('=');
+           std::string c= (*token).substr(s + 1, (*token).length());
+           if ( !c.empty() )
+               std::swap(color, c);
+       }
+       else if ( (*token).find("offsetx=", 0) != std::string::npos ) {
+           size_t s= (*token).find_first_of('=');
+           FB_istringstream o((*token).substr(s + 1, (*token).length()));
+           if ( !o.eof() ) {
+               o >> offx;
+           }
+       }
+       else if ( (*token).find("offsety=", 0) != std::string::npos ) {
+           size_t s= (*token).find_first_of('=');
+           FB_istringstream o((*token).substr(s + 1, (*token).length()));
+           if ( !o.eof() ) {
+               o >> offy;
+           }
+       }
+   }
+
+   return 1;
+
+};
+
+}; // end nameless namespace
+
+
+
 namespace FbTk {
 
 bool Font::m_multibyte = false; 
@@ -117,7 +202,10 @@ bool Font::m_utf8mode = false;
 
 Font::Font(const char *name, bool antialias):
     m_fontimp(0),
-    m_antialias(false), m_rotated(false), m_shadow(false),
+    m_antialias(false), m_rotated(false), 
+    m_shadow(false), m_shadow_color("#000000"), 
+    m_shadow_offx(1), m_shadow_offy(1),
+    m_halo(false), m_halo_color("#ffffff"),
     m_iconv((iconv_t)-1) {
 
     // MB_CUR_MAX returns the size of a char in the current locale
@@ -222,46 +310,49 @@ void Font::setAntialias(bool flag) {
 bool Font::load(const std::string &name) {
     if (name.size() == 0)
         return false;
-    // copy name so we can manipulate it
-    std::string new_name = name;
 
     m_shadow = false;
-
-    // find font option "shadow"	
-    size_t start_pos = new_name.find_first_of(':');
-    if (start_pos != std::string::npos) {        
-        size_t shadow_pos = new_name.find("shadow", start_pos);
-        if (shadow_pos != std::string::npos) {
-            m_shadow = true;
-            // erase "shadow" since it's not a valid option for the font
-            new_name.erase(shadow_pos, 6);
-            
-            // is the option row empty?
-            if (new_name.find_first_not_of("\t ,", start_pos + 1) == std::string::npos)
-                new_name.erase(start_pos); // erase the ':' and the rest of the line
-            else {
-                // there might be some options left so we need to remove the ","
-                // before/after "shadow" option
-                size_t pos = new_name.find_last_not_of("\t ", shadow_pos);
-                if (pos != std::string::npos) {
-                    if (new_name[pos] == ',')
-                        new_name.erase(pos, 1);
-                
+    m_halo = false;
+
+    // everything after ':' is a fontoption
+    // -> extract 'halo' and 'shadow' and
+    // load remaining fname
+    std::list< std::string > tokens;
+    size_t                   sep= name.find_first_of(':');
+    std::string              fname;
+
+    if ( sep != std::string::npos ) {
+        fname= std::string(name.c_str(), sep + 1);
+        FbTk::StringUtil::stringtok(tokens, name.substr(sep + 1, name.length()), ",");
                 }
-
-                // ok, we removed the "," and "shadow" now we need to determine
-                // if we need to remove the ":" , so we search for anything except
-                // \t and space and if we dont find anything the ":" is removed
-                if (new_name.find_first_not_of("\t ", start_pos + 1) == std::string::npos)
-                    new_name.erase(start_pos, 1);               
-
+    else
+        fname= name;
+
+    tokens.unique();
+    bool firstone= true;
+    std::list< std::string >::const_iterator token;
+
+    // check tokens and extract extraoptions for halo and shadow
+    for( token= tokens.begin(); token != tokens.end(); token++ ) {
+        if ( (*token).find("halo",0) != std::string::npos ) {
+            m_halo= true;
+            extract_halo_options(*token, m_halo_color);
+        }
+        else if ( (*token).find("shadow", 0) != std::string::npos ) {
+            m_shadow= true;
+            extract_shadow_options(*token, m_shadow_color, m_shadow_offx, m_shadow_offy);
             }
-
+        else {
+            if ( !firstone )
+              fname+= ", ";
+            else
+              firstone= false;
+            fname= fname + *token;
         }
     }
 
-    m_fontstr = name;
-    return m_fontimp->load(new_name.c_str());
+    m_fontstr = fname;
+    return m_fontimp->load(fname.c_str());
 }
 
 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,
 
     const char *real_text = rtext ? rtext : text;
 
-    // draw shadow first
-    if (first_run && m_shadow) {
+    // draw "effects" first
+    if (first_run) {
+        if (m_shadow) {
         FbTk::GContext shadow_gc(w);
-        shadow_gc.setForeground(FbTk::Color("black", screen));
-        first_run = false; // so we don't end up in a loop
-        drawText(w, screen, shadow_gc.gc(), real_text, len, x + 1, y + 1);
+            shadow_gc.setForeground(FbTk::Color(m_shadow_color.c_str(), screen));
+            first_run = false;
+            drawText(w, screen, shadow_gc.gc(), real_text, len,
+                     x + m_shadow_offx, y + m_shadow_offy, rotate);
         first_run = true;
+        } else if (m_halo) {
+            FbTk::GContext halo_gc(w);
+            halo_gc.setForeground(FbTk::Color(m_halo_color.c_str(), screen));
+            first_run = false;
+            drawText(w, screen, halo_gc.gc(), real_text, len, x + 1, y + 1, rotate);
+            drawText(w, screen, halo_gc.gc(), real_text, len, x - 1, y + 1, rotate);
+            drawText(w, screen, halo_gc.gc(), real_text, len, x - 1, y - 1, rotate);
+            drawText(w, screen, halo_gc.gc(), real_text, len, x + 1, y - 1, rotate);
+            first_run = true;
+        }
     }
 
     if (!rotate && isRotated()) {
diff --git a/src/FbTk/Font.hh b/src/FbTk/Font.hh
index fded0c4..1ac2fe0 100644
--- a/src/FbTk/Font.hh
+++ b/src/FbTk/Font.hh
@@ -19,7 +19,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-//$Id: Font.hh,v 1.8 2004/08/10 11:22:10 fluxgen Exp $
+//$Id: Font.hh,v 1.9 2004/08/10 18:08:37 fluxgen Exp $
 
 #ifndef FBTK_FONT_HH
 #define FBTK_FONT_HH
@@ -56,7 +56,8 @@ public:
     /// @return true if utf-8 mode is enabled, else false
     static bool utf8() { return m_utf8mode; }
     void setAntialias(bool flag);
-    inline void setShadow(bool flag) { m_shadow = flag; }
+    inline void setShadow(bool flag) { m_shadow = flag; if (m_shadow) setHalo(false); }
+    inline void setHalo(bool flag)   { m_halo = flag; if (m_halo) setShadow(false); }
     /**
        @param text text to check size
        @param size length of text in bytes
@@ -92,6 +93,7 @@ public:
     /// @return rotated angle
     float angle() const { return m_angle; }
     bool shadow() const { return m_shadow; }
+    bool halo() const { return m_halo; }
 private:
 	
     std::auto_ptr<FontImp> m_fontimp; ///< font implementation
@@ -102,6 +104,11 @@ private:
     bool m_rotated; ///< wheter we're rotated or not
     float m_angle; ///< rotation angle
     bool m_shadow; ///< shadow text
+    std::string m_shadow_color; ///< shadow color
+    int m_shadow_offx; ///< offset y for shadow
+    int m_shadow_offy; ///< offset x for shadow
+    bool m_halo; ///< halo text
+    std::string m_halo_color; ///< halo color
     std::string m_locale; ///< system encoding
     iconv_t m_iconv;
 };
-- 
cgit v0.11.2