diff options
author | Mathias Gumz <akira at fluxbox dot org> | 2012-10-02 12:24:47 (GMT) |
---|---|---|
committer | Mathias Gumz <akira at fluxbox dot org> | 2012-10-03 08:27:16 (GMT) |
commit | 7b6ab828c7e5453a2720462156d165707935c9ef (patch) | |
tree | 3b641791b20b1994935e149fd7461decb11bef8c /src | |
parent | 032a23d1e790c5224194562a837cc80fc157ce9b (diff) | |
download | fluxbox-7b6ab828c7e5453a2720462156d165707935c9ef.zip fluxbox-7b6ab828c7e5453a2720462156d165707935c9ef.tar.bz2 |
Improved vertical alignment of text in FbTk::TextButton
The old formula for vertical align text inside FbTk::TextButton ('height/2 +
font_ascent/2 - 1') produced not always good looking results, escpecially
when different fonts are involved (eg, ClockTool and WorkspaceName have
different fonts and font-sizes).
'(height - font_ascent) / 2 - 1' produces better results.
Additional changes:
* added ASCII-Art to document the involved entities when calculating the
baseline
* rewritten tests/testFont.cc to accept multiples texts and multiple
fonts
* removed some internal parts of FbTk::Font from the public interface
Diffstat (limited to 'src')
-rw-r--r-- | src/FbTk/Font.cc | 75 | ||||
-rw-r--r-- | src/FbTk/Font.hh | 17 | ||||
-rw-r--r-- | src/FbTk/TextButton.cc | 78 | ||||
-rw-r--r-- | src/FbTk/TextButton.hh | 4 | ||||
-rw-r--r-- | src/Toolbar.cc | 2 | ||||
-rw-r--r-- | src/tests/testFont.cc | 212 |
6 files changed, 215 insertions, 173 deletions
diff --git a/src/FbTk/Font.cc b/src/FbTk/Font.cc index 37621a8..544ddc2 100644 --- a/src/FbTk/Font.cc +++ b/src/FbTk/Font.cc | |||
@@ -66,6 +66,7 @@ | |||
66 | #include <map> | 66 | #include <map> |
67 | #include <typeinfo> | 67 | #include <typeinfo> |
68 | #include <langinfo.h> | 68 | #include <langinfo.h> |
69 | #include <cstdio> | ||
69 | 70 | ||
70 | #include <errno.h> | 71 | #include <errno.h> |
71 | 72 | ||
@@ -83,12 +84,10 @@ namespace { | |||
83 | // use to map <font1>|<font2>|<font3> => <fontthatworks> | 84 | // use to map <font1>|<font2>|<font3> => <fontthatworks> |
84 | typedef map<string, string> StringMap; | 85 | typedef map<string, string> StringMap; |
85 | typedef StringMap::iterator StringMapIt; | 86 | typedef StringMap::iterator StringMapIt; |
86 | StringMap lookup_map; | ||
87 | 87 | ||
88 | // stores <fontthatworks and the fontimp | 88 | // stores <fontthatworks and the fontimp |
89 | typedef map<string, FbTk::FontImp* > FontCache; | 89 | typedef map<string, FbTk::FontImp* > FontCache; |
90 | typedef FontCache::iterator FontCacheIt; | 90 | typedef FontCache::iterator FontCacheIt; |
91 | FontCache font_cache; | ||
92 | 91 | ||
93 | 92 | ||
94 | void resetEffects(FbTk::Font& font) { | 93 | void resetEffects(FbTk::Font& font) { |
@@ -100,24 +99,30 @@ void resetEffects(FbTk::Font& font) { | |||
100 | font.setShadowOffX(2); | 99 | font.setShadowOffX(2); |
101 | } | 100 | } |
102 | 101 | ||
102 | |||
103 | StringMap s_lookup_map; | ||
104 | FontCache s_font_cache; | ||
105 | bool s_multibyte = false; // if the fontimp should be a multibyte font | ||
106 | bool s_utf8mode = false; // should the font use utf8 font imp | ||
107 | |||
108 | |||
103 | } // end nameless namespace | 109 | } // end nameless namespace |
104 | 110 | ||
105 | 111 | ||
106 | 112 | ||
107 | namespace FbTk { | 113 | namespace FbTk { |
108 | 114 | ||
109 | bool Font::s_multibyte = false; | 115 | const char Font::DEFAULT_FONT[] = "__DEFAULT__"; |
110 | bool Font::s_utf8mode = false; | ||
111 | 116 | ||
112 | 117 | ||
113 | void Font::shutdown() { | 118 | void Font::shutdown() { |
114 | 119 | ||
115 | FontCacheIt fit; | 120 | FontCacheIt fit; |
116 | for (fit = font_cache.begin(); fit != font_cache.end(); fit++) { | 121 | for (fit = s_font_cache.begin(); fit != s_font_cache.end(); ++fit) { |
117 | FontImp* font = fit->second; | 122 | FontImp* font = fit->second; |
118 | if (font) { | 123 | if (font) { |
119 | FontCacheIt it; | 124 | FontCacheIt it; |
120 | for (it = fit; it != font_cache.end(); ++it) | 125 | for (it = fit; it != s_font_cache.end(); ++it) |
121 | if (it->second == font) | 126 | if (it->second == font) |
122 | it->second = 0; | 127 | it->second = 0; |
123 | delete font; | 128 | delete font; |
@@ -125,6 +130,15 @@ void Font::shutdown() { | |||
125 | } | 130 | } |
126 | } | 131 | } |
127 | 132 | ||
133 | bool Font::multibyte() { | ||
134 | return s_multibyte; | ||
135 | } | ||
136 | |||
137 | bool Font::utf8() { | ||
138 | return s_utf8mode; | ||
139 | } | ||
140 | |||
141 | |||
128 | Font::Font(const char *name): | 142 | Font::Font(const char *name): |
129 | m_fontimp(0), | 143 | m_fontimp(0), |
130 | m_shadow(false), m_shadow_color("black", DefaultScreen(App::instance()->display())), | 144 | m_shadow(false), m_shadow_color("black", DefaultScreen(App::instance()->display())), |
@@ -135,13 +149,15 @@ Font::Font(const char *name): | |||
135 | if (MB_CUR_MAX > 1) // more than one byte, then we're multibyte | 149 | if (MB_CUR_MAX > 1) // more than one byte, then we're multibyte |
136 | s_multibyte = true; | 150 | s_multibyte = true; |
137 | 151 | ||
138 | // check for utf-8 mode | 152 | |
139 | #if defined(CODESET) && !defined(_WIN32) | ||
140 | char *locale_codeset = nl_langinfo(CODESET); | ||
141 | #else // openbsd doesnt have this (yet?) | ||
142 | char *locale_codeset = 0; | 153 | char *locale_codeset = 0; |
143 | #endif // defined(CODESET) && !defined(_WIN32) | ||
144 | 154 | ||
155 | // openbsd doesnt have this (yet?) | ||
156 | #if defined(CODESET) && !defined(_WIN32) | ||
157 | locale_codeset = nl_langinfo(CODESET); | ||
158 | #endif | ||
159 | |||
160 | // check for utf-8 mode | ||
145 | if (locale_codeset && strcmp("UTF-8", locale_codeset) == 0) { | 161 | if (locale_codeset && strcmp("UTF-8", locale_codeset) == 0) { |
146 | s_utf8mode = true; | 162 | s_utf8mode = true; |
147 | } else if (locale_codeset != 0) { | 163 | } else if (locale_codeset != 0) { |
@@ -159,15 +175,15 @@ Font::~Font() { | |||
159 | 175 | ||
160 | bool Font::load(const string &name) { | 176 | bool Font::load(const string &name) { |
161 | 177 | ||
162 | if (name.size() == 0) | 178 | if (name.empty()) |
163 | return false; | 179 | return false; |
164 | 180 | ||
165 | StringMapIt lookup_entry; | 181 | StringMapIt lookup_entry; |
166 | FontCacheIt cache_entry; | 182 | FontCacheIt cache_entry; |
167 | 183 | ||
168 | // check if one of <font1>|<font2>|<font3> is already there | 184 | // check if one of <font1>|<font2>|<font3> is already there |
169 | if ((lookup_entry = lookup_map.find(name)) != lookup_map.end() && | 185 | if ((lookup_entry = s_lookup_map.find(name)) != s_lookup_map.end() && |
170 | (cache_entry = font_cache.find(lookup_entry->second)) != font_cache.end()) { | 186 | (cache_entry = s_font_cache.find(lookup_entry->second)) != s_font_cache.end()) { |
171 | m_fontstr = cache_entry->first; | 187 | m_fontstr = cache_entry->first; |
172 | m_fontimp = cache_entry->second; | 188 | m_fontimp = cache_entry->second; |
173 | resetEffects(*this); | 189 | resetEffects(*this); |
@@ -185,10 +201,10 @@ bool Font::load(const string &name) { | |||
185 | FbTk::StringUtil::removeTrailingWhitespace(*name_it); | 201 | FbTk::StringUtil::removeTrailingWhitespace(*name_it); |
186 | FbTk::StringUtil::removeFirstWhitespace(*name_it); | 202 | FbTk::StringUtil::removeFirstWhitespace(*name_it); |
187 | 203 | ||
188 | if ((cache_entry = font_cache.find(*name_it)) != font_cache.end()) { | 204 | if ((cache_entry = s_font_cache.find(*name_it)) != s_font_cache.end()) { |
189 | m_fontstr = cache_entry->first; | 205 | m_fontstr = cache_entry->first; |
190 | m_fontimp = cache_entry->second; | 206 | m_fontimp = cache_entry->second; |
191 | lookup_map[name] = m_fontstr; | 207 | s_lookup_map[name] = m_fontstr; |
192 | resetEffects(*this); | 208 | resetEffects(*this); |
193 | return true; | 209 | return true; |
194 | } | 210 | } |
@@ -210,32 +226,33 @@ bool Font::load(const string &name) { | |||
210 | #ifdef USE_XFT | 226 | #ifdef USE_XFT |
211 | if ((*name_it)[0] != '-') { | 227 | if ((*name_it)[0] != '-') { |
212 | 228 | ||
213 | if (*name_it == "__DEFAULT__") | 229 | if (*name_it == Font::DEFAULT_FONT) |
214 | realname = "monospace"; | 230 | realname = "monospace"; |
215 | 231 | ||
216 | tmp_font = new XftFontImp(0, s_utf8mode); | 232 | tmp_font = new XftFontImp(0, utf8()); |
217 | } | 233 | } |
218 | #endif // USE_XFT | 234 | #endif // USE_XFT |
219 | 235 | ||
220 | if (!tmp_font) { | 236 | if (!tmp_font) { |
221 | if (*name_it == "__DEFAULT__") | 237 | if (*name_it == Font::DEFAULT_FONT) |
222 | realname = "fixed"; | 238 | realname = "fixed"; |
223 | 239 | ||
224 | #ifdef USE_XMB | 240 | #ifdef USE_XMB |
225 | 241 | ||
226 | if (s_multibyte || s_utf8mode) { | 242 | if (multibyte() || utf8()) { |
227 | tmp_font = new XmbFontImp(0, s_utf8mode); | 243 | tmp_font = new XmbFontImp(0, utf8()); |
228 | } else // basic font implementation | 244 | } |
229 | #endif // USE_XMB | 245 | #endif // USE_XMB |
230 | { | 246 | } |
231 | tmp_font = new XFontImp(); | 247 | |
232 | } | 248 | if (!tmp_font) { |
249 | tmp_font = new XFontImp(); | ||
233 | } | 250 | } |
234 | 251 | ||
235 | if (tmp_font && tmp_font->load(realname.c_str())) { | 252 | if (tmp_font && tmp_font->load(realname.c_str())) { |
236 | lookup_map[name] = (*name_it); | 253 | s_lookup_map[name] = (*name_it); |
237 | m_fontimp = tmp_font; | 254 | m_fontimp = tmp_font; |
238 | font_cache[(*name_it)] = tmp_font; | 255 | s_font_cache[(*name_it)] = tmp_font; |
239 | m_fontstr = name; | 256 | m_fontstr = name; |
240 | resetEffects(*this); | 257 | resetEffects(*this); |
241 | return true; | 258 | return true; |
@@ -251,6 +268,10 @@ unsigned int Font::textWidth(const char* text, unsigned int size) const { | |||
251 | return m_fontimp->textWidth(text, size); | 268 | return m_fontimp->textWidth(text, size); |
252 | } | 269 | } |
253 | 270 | ||
271 | unsigned int Font::textWidth(const BiDiString &text) const { | ||
272 | return textWidth(text.visual().c_str(), text.visual().size()); | ||
273 | } | ||
274 | |||
254 | unsigned int Font::height() const { | 275 | unsigned int Font::height() const { |
255 | return m_fontimp->height(); | 276 | return m_fontimp->height(); |
256 | } | 277 | } |
diff --git a/src/FbTk/Font.hh b/src/FbTk/Font.hh index fb399d9..6ea2571 100644 --- a/src/FbTk/Font.hh +++ b/src/FbTk/Font.hh | |||
@@ -43,17 +43,19 @@ class FbDrawable; | |||
43 | class Font { | 43 | class Font { |
44 | public: | 44 | public: |
45 | 45 | ||
46 | static const char DEFAULT_FONT[]; | ||
47 | |||
48 | |||
46 | /// called at FbTk::App destruction time, cleans up cache | 49 | /// called at FbTk::App destruction time, cleans up cache |
47 | static void shutdown(); | 50 | static void shutdown(); |
48 | 51 | ||
49 | /// @return true if multibyte is enabled, else false | 52 | /// @return true if multibyte is enabled, else false |
50 | static bool multibyte() { return s_multibyte; } | 53 | static bool multibyte(); |
51 | /// @return true if utf-8 mode is enabled, else false | 54 | /// @return true if utf-8 mode is enabled, else false |
52 | static bool utf8() { return s_utf8mode; } | 55 | static bool utf8(); |
53 | |||
54 | 56 | ||
55 | 57 | ||
56 | explicit Font(const char *name = "__DEFAULT__"); | 58 | explicit Font(const char* name = DEFAULT_FONT); |
57 | virtual ~Font(); | 59 | virtual ~Font(); |
58 | /** | 60 | /** |
59 | Load a font | 61 | Load a font |
@@ -76,9 +78,7 @@ public: | |||
76 | @return size of text in pixels | 78 | @return size of text in pixels |
77 | */ | 79 | */ |
78 | unsigned int textWidth(const char* text, unsigned int size) const; | 80 | unsigned int textWidth(const char* text, unsigned int size) const; |
79 | unsigned int textWidth(const BiDiString &text) const { | 81 | unsigned int textWidth(const BiDiString &text) const; |
80 | return textWidth(text.visual().c_str(), text.visual().size()); | ||
81 | } | ||
82 | 82 | ||
83 | unsigned int height() const; | 83 | unsigned int height() const; |
84 | int ascent() const; | 84 | int ascent() const; |
@@ -119,9 +119,6 @@ private: | |||
119 | FbTk::FontImp* m_fontimp; ///< font implementation | 119 | FbTk::FontImp* m_fontimp; ///< font implementation |
120 | std::string m_fontstr; ///< font name | 120 | std::string m_fontstr; ///< font name |
121 | 121 | ||
122 | static bool s_multibyte; ///< if the fontimp should be a multibyte font | ||
123 | static bool s_utf8mode; ///< should the font use utf8 font imp | ||
124 | |||
125 | int m_angle; ///< rotation angle | 122 | int m_angle; ///< rotation angle |
126 | bool m_shadow; ///< shadow text | 123 | bool m_shadow; ///< shadow text |
127 | Color m_shadow_color; ///< shadow color | 124 | Color m_shadow_color; ///< shadow color |
diff --git a/src/FbTk/TextButton.cc b/src/FbTk/TextButton.cc index c31e3d6..33a2b44 100644 --- a/src/FbTk/TextButton.cc +++ b/src/FbTk/TextButton.cc | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "TextUtils.hh" | 23 | #include "TextUtils.hh" |
24 | #include "Font.hh" | 24 | #include "Font.hh" |
25 | #include "GContext.hh" | 25 | #include "GContext.hh" |
26 | #include <cstdio> | ||
26 | 27 | ||
27 | namespace FbTk { | 28 | namespace FbTk { |
28 | 29 | ||
@@ -62,16 +63,18 @@ void TextButton::setJustify(FbTk::Justify just) { | |||
62 | } | 63 | } |
63 | 64 | ||
64 | bool TextButton::setOrientation(FbTk::Orientation orient) { | 65 | bool TextButton::setOrientation(FbTk::Orientation orient) { |
66 | |||
65 | if (orient == m_orientation | 67 | if (orient == m_orientation |
66 | || !m_font->validOrientation(orient)) | 68 | || !m_font->validOrientation(orient)) |
67 | return false; | 69 | return false; |
70 | |||
68 | invalidateBackground(); | 71 | invalidateBackground(); |
69 | 72 | ||
70 | if (((m_orientation == FbTk::ROT0 || m_orientation == FbTk::ROT180) && | 73 | if (((m_orientation == FbTk::ROT0 || m_orientation == FbTk::ROT180) && |
71 | (orient == FbTk::ROT90 || orient == FbTk::ROT270)) || | 74 | (orient == FbTk::ROT90 || orient == FbTk::ROT270)) || |
72 | ((m_orientation == FbTk::ROT90 || m_orientation == FbTk::ROT270) && | 75 | ((m_orientation == FbTk::ROT90 || m_orientation == FbTk::ROT270) && |
73 | (orient == FbTk::ROT0 || orient == FbTk::ROT180))) { | 76 | (orient == FbTk::ROT0 || orient == FbTk::ROT180))) { |
74 | // flip width and height | 77 | |
75 | m_orientation = orient; | 78 | m_orientation = orient; |
76 | resize(height(), width()); | 79 | resize(height(), width()); |
77 | } else { | 80 | } else { |
@@ -112,8 +115,7 @@ void TextButton::setTextPadding(unsigned int padding) { | |||
112 | 115 | ||
113 | /// clear window and redraw text | 116 | /// clear window and redraw text |
114 | void TextButton::clear() { | 117 | void TextButton::clear() { |
115 | TextButton::clearArea(0, 0, | 118 | TextButton::clearArea(0, 0, width(), height()); |
116 | width(), height()); | ||
117 | } | 119 | } |
118 | 120 | ||
119 | void TextButton::clearArea(int x, int y, | 121 | void TextButton::clearArea(int x, int y, |
@@ -135,34 +137,58 @@ void TextButton::renderForeground(FbWindow &win, FbDrawable &drawable) { | |||
135 | } | 137 | } |
136 | 138 | ||
137 | void TextButton::drawText(int x_offset, int y_offset, FbDrawable *drawable) { | 139 | void TextButton::drawText(int x_offset, int y_offset, FbDrawable *drawable) { |
140 | |||
141 | if (drawable == 0) | ||
142 | drawable = this; | ||
143 | |||
138 | const FbString& visual = text().visual(); | 144 | const FbString& visual = text().visual(); |
139 | unsigned int textlen = visual.size(); | 145 | unsigned int textlen = visual.size(); |
140 | unsigned int textw = width(); | 146 | unsigned int button_width = width(); |
141 | unsigned int texth = height(); | 147 | unsigned int button_height = height(); |
142 | translateSize(m_orientation, textw, texth); | 148 | |
149 | translateSize(m_orientation, button_width, button_height); | ||
143 | 150 | ||
144 | int align_x = FbTk::doAlignment(textw - x_offset - m_left_padding - m_right_padding, | 151 | // horizontal alignment, cut off text if needed |
152 | int align_x = FbTk::doAlignment(button_width - x_offset - m_left_padding - m_right_padding, | ||
145 | bevel(), justify(), font(), | 153 | bevel(), justify(), font(), |
146 | visual.data(), visual.size(), | 154 | visual.data(), visual.size(), |
147 | textlen); // return new text len | 155 | textlen); // return new text len |
148 | 156 | ||
149 | // center text by default | 157 | // |
150 | int center_pos = texth/2 + font().ascent()/2 - 1; | 158 | // we center the text vertically. to do this we have to nudge the |
151 | 159 | // baseline a little bit down so the "middle" of the glyph is placed | |
152 | int textx = align_x + x_offset + m_left_padding; | 160 | // on the middle of the button. we "assume", that ascent/2 is roughly |
153 | int texty = center_pos + y_offset; | 161 | // the middle of the glyph. example: |
154 | 162 | // | |
155 | if (drawable == 0) | 163 | // +== ascent <--------->== +===================== |
156 | drawable = this; | 164 | // | | | | |
165 | // | | ggggg | | ascent <---------> | ||
166 | // | | g gg | | | | | ||
167 | // | baseline < glyph | | | ggggg | | ||
168 | // | | g | -- middle of button -- | | g gg | | ||
169 | // | descent < ggggg | | baseline < glyph | | ||
170 | // | height |_________| | | g | | ||
171 | // | | descent < ggggg | | ||
172 | // | | height |_________| | ||
173 | // | | | ||
174 | // +======================= +===================== | ||
175 | // | ||
176 | // ascent = 4 | ||
177 | // button_height = 11 | ||
178 | // baseline = (11 + 4) / 2 - 1 = 6 | ||
179 | // | ||
180 | |||
181 | int baseline_x = align_x + x_offset + m_left_padding; | ||
182 | int baseline_y = ((button_height + font().ascent()) / 2) - 1 + y_offset; | ||
183 | |||
184 | // TODO: remove debug output fprintf(stderr, "%d | %d %d %d\n", height(), font().height(), font().ascent(), font().descent()); | ||
157 | 185 | ||
158 | // give it ROT0 style coords | 186 | // give it ROT0 style coords |
159 | translateCoords(m_orientation, textx, texty, textw, texth); | 187 | translateCoords(m_orientation, baseline_x, baseline_y, button_width, button_height); |
160 | 188 | ||
161 | font().drawText(*drawable, | 189 | font().drawText(*drawable, screenNumber(), gc(), |
162 | screenNumber(), | 190 | visual.c_str(), textlen, |
163 | gc(), // graphic context | 191 | baseline_x, baseline_y, m_orientation); |
164 | visual.c_str(), textlen, // string and string size | ||
165 | textx, texty, m_orientation); // position | ||
166 | } | 192 | } |
167 | 193 | ||
168 | 194 | ||
@@ -170,15 +196,15 @@ bool TextButton::textExceeds(int x_offset) { | |||
170 | 196 | ||
171 | const FbString& visual = text().visual(); | 197 | const FbString& visual = text().visual(); |
172 | unsigned int textlen = visual.size(); | 198 | unsigned int textlen = visual.size(); |
173 | unsigned int textw = width(); | 199 | unsigned int button_width = width(); |
174 | unsigned int texth = height(); | 200 | unsigned int button_height = height(); |
175 | translateSize(m_orientation, textw, texth); | 201 | translateSize(m_orientation, button_width, button_height); |
176 | 202 | ||
177 | FbTk::doAlignment(textw - x_offset - m_left_padding - m_right_padding, | 203 | FbTk::doAlignment(button_width - x_offset - m_left_padding - m_right_padding, |
178 | bevel(), justify(), font(), visual.data(), visual.size(), | 204 | bevel(), justify(), font(), visual.data(), visual.size(), |
179 | textlen); // return new text len | 205 | textlen); // return new text len |
180 | 206 | ||
181 | return visual.size()>textlen; | 207 | return visual.size() > textlen; |
182 | } | 208 | } |
183 | 209 | ||
184 | void TextButton::exposeEvent(XExposeEvent &event) { | 210 | void TextButton::exposeEvent(XExposeEvent &event) { |
diff --git a/src/FbTk/TextButton.hh b/src/FbTk/TextButton.hh index a1c8b0e..eb0beca 100644 --- a/src/FbTk/TextButton.hh +++ b/src/FbTk/TextButton.hh | |||
@@ -56,7 +56,8 @@ public: | |||
56 | 56 | ||
57 | void exposeEvent(XExposeEvent &event); | 57 | void exposeEvent(XExposeEvent &event); |
58 | 58 | ||
59 | void renderForeground(FbDrawable &drawable); | 59 | //void renderForeground(FbDrawable &drawable); |
60 | void renderForeground(FbWindow &win, FbDrawable &drawable); | ||
60 | 61 | ||
61 | FbTk::Justify justify() const { return m_justify; } | 62 | FbTk::Justify justify() const { return m_justify; } |
62 | const BiDiString &text() const { return m_text; } | 63 | const BiDiString &text() const { return m_text; } |
@@ -65,7 +66,6 @@ public: | |||
65 | unsigned int textWidth() const; | 66 | unsigned int textWidth() const; |
66 | int bevel() const { return m_bevel; } | 67 | int bevel() const { return m_bevel; } |
67 | 68 | ||
68 | void renderForeground(FbWindow &win, FbDrawable &drawable); | ||
69 | 69 | ||
70 | protected: | 70 | protected: |
71 | virtual void drawText(int x_offset, int y_offset, FbDrawable *drawable_override); | 71 | virtual void drawText(int x_offset, int y_offset, FbDrawable *drawable_override); |
diff --git a/src/Toolbar.cc b/src/Toolbar.cc index 1c22440..f46b9e9 100644 --- a/src/Toolbar.cc +++ b/src/Toolbar.cc | |||
@@ -170,14 +170,12 @@ Toolbar::Frame::Frame(FbTk::EventHandler &evh, int screen_num): | |||
170 | { | 170 | { |
171 | 171 | ||
172 | FbTk::EventManager &evm = *FbTk::EventManager::instance(); | 172 | FbTk::EventManager &evm = *FbTk::EventManager::instance(); |
173 | // add windows to eventmanager | ||
174 | evm.add(evh, window); | 173 | evm.add(evh, window); |
175 | 174 | ||
176 | } | 175 | } |
177 | 176 | ||
178 | Toolbar::Frame::~Frame() { | 177 | Toolbar::Frame::~Frame() { |
179 | FbTk::EventManager &evm = *FbTk::EventManager::instance(); | 178 | FbTk::EventManager &evm = *FbTk::EventManager::instance(); |
180 | // remove windows from eventmanager | ||
181 | evm.remove(window); | 179 | evm.remove(window); |
182 | } | 180 | } |
183 | 181 | ||
diff --git a/src/tests/testFont.cc b/src/tests/testFont.cc index 1ba63f7..3fdc0a6 100644 --- a/src/tests/testFont.cc +++ b/src/tests/testFont.cc | |||
@@ -19,13 +19,16 @@ | |||
19 | // DEALINGS IN THE SOFTWARE. | 19 | // DEALINGS IN THE SOFTWARE. |
20 | 20 | ||
21 | #include "FbTk/App.hh" | 21 | #include "FbTk/App.hh" |
22 | #include "FbTk/FbString.hh" | ||
22 | #include "FbTk/FbWindow.hh" | 23 | #include "FbTk/FbWindow.hh" |
23 | #include "FbTk/Font.hh" | 24 | #include "FbTk/Font.hh" |
25 | #include "FbTk/TextButton.hh" | ||
24 | #include "FbTk/EventHandler.hh" | 26 | #include "FbTk/EventHandler.hh" |
25 | #include "FbTk/EventManager.hh" | 27 | #include "FbTk/EventManager.hh" |
26 | #include "FbTk/GContext.hh" | 28 | #include "FbTk/GContext.hh" |
27 | #include "FbTk/Color.hh" | 29 | #include "FbTk/Color.hh" |
28 | #include "FbTk/FbString.hh" | 30 | #include "FbTk/FbString.hh" |
31 | #include "FbTk/StringUtil.hh" | ||
29 | 32 | ||
30 | #include <X11/Xutil.h> | 33 | #include <X11/Xutil.h> |
31 | #include <X11/keysym.h> | 34 | #include <X11/keysym.h> |
@@ -34,124 +37,103 @@ | |||
34 | #include <cstring> | 37 | #include <cstring> |
35 | #include <cstdlib> | 38 | #include <cstdlib> |
36 | #include <iostream> | 39 | #include <iostream> |
40 | #include <vector> | ||
37 | using namespace std; | 41 | using namespace std; |
38 | 42 | ||
39 | class App:public FbTk::App, public FbTk::EventHandler { | 43 | |
44 | class App:public FbTk::App, public FbTk::FbWindow, public FbTk::EventHandler { | ||
40 | public: | 45 | public: |
41 | App(const char *displayname, const string &foreground, const string background): | 46 | App(const char *displayname, const string& foreground, const string& background): |
42 | FbTk::App(displayname), | 47 | FbTk::App(displayname), |
43 | m_win(DefaultScreen(display()), | 48 | FbTk::FbWindow(DefaultScreen(this->FbTk::App::display()), 0, 0, 640, 480, KeyPressMask|ExposureMask|StructureNotifyMask), |
44 | 0, 0, 640, 480, KeyPressMask | ExposureMask) { | 49 | m_gc(drawable()), |
45 | m_background = background; | 50 | m_foreground(foreground.c_str(), screenNumber()), |
46 | m_foreground = foreground; | 51 | m_background(background.c_str(), screenNumber()) { |
47 | m_orient = FbTk::ROT0; | 52 | |
48 | m_win.show(); | 53 | m_gc.setLineAttributes(1, FbTk::GContext::JOINMITER, FbTk::GContext::LINESOLID, FbTk::GContext::CAPNOTLAST); |
49 | m_win.setBackgroundColor(FbTk::Color(background.c_str(), m_win.screenNumber())); | 54 | m_gc.setForeground(m_foreground); |
50 | FbTk::EventManager::instance()->add(*this, m_win); | 55 | m_gc.setBackground(m_background); |
51 | } | 56 | setBackgroundColor(m_background); |
52 | ~App() { | 57 | |
58 | FbTk::EventManager::instance()->add(*this, *this); | ||
53 | } | 59 | } |
60 | |||
61 | ~App() { } | ||
62 | |||
54 | void keyPressEvent(XKeyEvent &ke) { | 63 | void keyPressEvent(XKeyEvent &ke) { |
55 | KeySym ks; | 64 | KeySym ks; |
56 | char keychar[1]; | 65 | char keychar[1]; |
57 | XLookupString(&ke, keychar, 1, &ks, 0); | 66 | XLookupString(&ke, keychar, 1, &ks, 0); |
58 | if (ks == XK_Escape) | 67 | if (ks == XK_Escape) { |
59 | end(); | 68 | end(); |
60 | /* | 69 | } |
61 | else { // toggle antialias | ||
62 | m_font.setAntialias(!m_font.isAntialias()); | ||
63 | cerr<<boolalpha; | ||
64 | cerr<<"antialias: "<<m_font.isAntialias()<<endl; | ||
65 | redraw(); | ||
66 | } */ | ||
67 | } | 70 | } |
68 | 71 | ||
72 | virtual void handleEvent(XEvent& event) { | ||
73 | if (event.type == ConfigureNotify) { | ||
74 | resize(event.xconfigure.width, event.xconfigure.height); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | |||
69 | void exposeEvent(XExposeEvent &event) { | 79 | void exposeEvent(XExposeEvent &event) { |
70 | redraw(); | 80 | redraw(); |
71 | } | 81 | } |
72 | 82 | ||
73 | void redraw() { | 83 | void redraw() { |
74 | size_t text_w = m_font.textWidth(m_text.c_str(), m_text.size()); | 84 | size_t i; |
75 | int mult = 1; | 85 | for (i = 0; i < m_buttons.size(); ++i) { |
76 | if (m_orient == FbTk::ROT180) | 86 | FbTk::TextButton* b = m_buttons[i]; |
77 | mult = -1; | 87 | b->clear(); |
78 | size_t text_h = m_font.height(); | 88 | b->drawLine(m_gc.gc(), 0, b->height() / 2, b->width(), b->height() / 2); |
79 | int x = 640/2 - mult* text_w/2; | ||
80 | int y = 480/2 - mult*text_h/2; | ||
81 | m_win.clear(); | ||
82 | FbTk::GContext wingc(m_win.drawable()); | ||
83 | |||
84 | int bx1 = 0; | ||
85 | int by1 = 0; | ||
86 | int bx2 = text_w; | ||
87 | int by2 = 0; | ||
88 | |||
89 | switch (m_orient) { | ||
90 | case FbTk::ROT90: | ||
91 | by2 = bx2; | ||
92 | bx2 = 0; | ||
93 | break; | ||
94 | case FbTk::ROT180: | ||
95 | bx2 = -bx2; | ||
96 | break; | ||
97 | case FbTk::ROT270: | ||
98 | by2 = -bx2; | ||
99 | bx2 = 0; | ||
100 | break; | ||
101 | default: | ||
102 | break; | ||
103 | } | 89 | } |
90 | this->clear(); | ||
91 | } | ||
104 | 92 | ||
105 | /* | 93 | void resize(unsigned int width, unsigned int height) { |
106 | m_win.drawLine(wingc.gc(), | 94 | FbTk::FbWindow::resize(width, height); |
107 | x, y + m_font.descent(), | 95 | unsigned w = width / m_buttons.size(); |
108 | x + text_w, y + m_font.descent()); | 96 | size_t i; |
109 | m_win.drawLine(wingc.gc(), | 97 | for (i = 0; i < m_buttons.size(); ++i) { |
110 | x, y - text_h, | 98 | m_buttons[i]->moveResize(i * w, 0, w, height); |
111 | x + text_w, y - text_h); | 99 | } |
112 | */ | 100 | redraw(); |
113 | // draw the baseline in red | ||
114 | wingc.setForeground(FbTk::Color("red", m_win.screenNumber())); | ||
115 | m_win.drawLine(wingc.gc(), | ||
116 | x + bx1, y + by1, x + bx2, y+by2); | ||
117 | wingc.setForeground(FbTk::Color(m_foreground.c_str(), m_win.screenNumber())); | ||
118 | cerr<<"text size "<<text_w<<"x"<<text_h<<endl; | ||
119 | m_font.drawText(m_win, | ||
120 | 0, wingc.gc(), | ||
121 | m_text.c_str(), m_text.size(), | ||
122 | x, y, m_orient); | ||
123 | |||
124 | } | 101 | } |
125 | 102 | ||
126 | FbTk::Font &font() { return m_font; } | 103 | void addText(const FbTk::BiDiString& text, FbTk::Font& font, const FbTk::Orientation orient) { |
127 | void setText(const std::string& text, const FbTk::Orientation orient) { m_text = text; m_orient = orient; } | 104 | |
105 | FbTk::FbWindow* win = this; | ||
106 | FbTk::TextButton* button = new FbTk::TextButton(*win, font, text); | ||
107 | |||
108 | button->setGC(m_gc.gc()); | ||
109 | button->setOrientation(orient); | ||
110 | button->setBackgroundColor(m_background); | ||
111 | button->show(); | ||
112 | |||
113 | m_buttons.push_back(button); | ||
114 | } | ||
128 | 115 | ||
129 | private: | 116 | private: |
130 | string m_foreground, m_background; | 117 | vector<FbTk::TextButton*> m_buttons; |
131 | FbTk::FbWindow m_win; | 118 | FbTk::GContext m_gc; |
132 | FbTk::Font m_font; | 119 | FbTk::Color m_foreground; |
133 | FbTk::Orientation m_orient; | 120 | FbTk::Color m_background; |
134 | string m_text; | ||
135 | }; | 121 | }; |
136 | 122 | ||
123 | |||
124 | |||
137 | int main(int argc, char **argv) { | 125 | int main(int argc, char **argv) { |
138 | //bool antialias = false; | 126 | |
127 | vector<string> texts_and_fonts; | ||
139 | FbTk::Orientation orient = FbTk::ROT0; | 128 | FbTk::Orientation orient = FbTk::ROT0; |
140 | bool xft = false; | ||
141 | string fontname(""); | ||
142 | string displayname(""); | 129 | string displayname(""); |
143 | string background("black"); | 130 | string background("white"); |
144 | string foreground("white"); | 131 | string foreground("black"); |
145 | string text("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.-_¯åäöÅÄÖ^~+=`\"!#¤%&/()=¡@£$½¥{[]}¶½§±"); | 132 | |
146 | for (int a=1; a<argc; ++a) { | 133 | int a; |
147 | if (strcmp("-font", argv[a])==0 && a + 1 < argc) { | 134 | for (a = 1; a < argc; ++a) { |
148 | fontname = argv[++a]; | 135 | if (strcmp("-display", argv[a]) == 0 && a + 1 < argc) { |
149 | } else if (strcmp("-xft", argv[a])==0) { | ||
150 | xft = true; | ||
151 | } else if (strcmp("-display", argv[a]) == 0 && a + 1 < argc) { | ||
152 | displayname = argv[++a]; | 136 | displayname = argv[++a]; |
153 | } else if (strcmp("-text", argv[a]) == 0 && a + 1 < argc) { | ||
154 | text = argv[++a]; | ||
155 | } else if (strcmp("-orient", argv[a]) == 0) { | 137 | } else if (strcmp("-orient", argv[a]) == 0) { |
156 | orient = (FbTk::Orientation) (atoi(argv[++a]) % 4); | 138 | orient = (FbTk::Orientation) (atoi(argv[++a]) % 4); |
157 | } else if (strcmp("-bg", argv[a]) == 0 && a + 1 < argc) { | 139 | } else if (strcmp("-bg", argv[a]) == 0 && a + 1 < argc) { |
@@ -159,35 +141,53 @@ int main(int argc, char **argv) { | |||
159 | } else if (strcmp("-fg", argv[a]) == 0 && a + 1 < argc) { | 141 | } else if (strcmp("-fg", argv[a]) == 0 && a + 1 < argc) { |
160 | foreground = argv[++a]; | 142 | foreground = argv[++a]; |
161 | } else if (strcmp("-h", argv[a]) == 0) { | 143 | } else if (strcmp("-h", argv[a]) == 0) { |
162 | cerr<<"Arguments: "<<endl; | 144 | cerr<<"Arguments: \"text|fontname\" [\"text|fontname2\"]"<<endl; |
163 | cerr<<"-font <fontname>"<<endl; | ||
164 | // cerr<<"-antialias"<<endl; | ||
165 | cerr<<"-display <display>"<<endl; | 145 | cerr<<"-display <display>"<<endl; |
166 | cerr<<"-text <text>"<<endl; | ||
167 | cerr<<"-orient"<<endl; | 146 | cerr<<"-orient"<<endl; |
168 | cerr<<"-fg <foreground color>"<<endl; | 147 | cerr<<"-fg <foreground color>"<<endl; |
169 | cerr<<"-bg <background color>"<<endl; | 148 | cerr<<"-bg <background color>"<<endl; |
170 | cerr<<"-h"<<endl; | 149 | cerr<<"-h"<<endl; |
171 | exit(0); | 150 | exit(0); |
151 | } else { | ||
152 | texts_and_fonts.push_back(argv[a]); | ||
172 | } | 153 | } |
173 | |||
174 | } | 154 | } |
175 | |||
176 | 155 | ||
177 | App app(displayname.c_str(), foreground, background); | 156 | if (texts_and_fonts.empty()) { |
178 | //app.font().setAntialias(antialias); | 157 | texts_and_fonts.push_back("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.-_¯åäöÅÄÖ^~+=`\"!#¤%&/()=¡@£$½¥{[]}¶½§±|default"); |
179 | if (!app.font().load(fontname.c_str())) | ||
180 | cerr<<"Failed to load: "<<fontname<<endl; | ||
181 | if (orient && !app.font().validOrientation(orient)) { | ||
182 | cerr<<"Orientation not valid ("<<orient<<")"<<endl; | ||
183 | orient = FbTk::ROT0; | ||
184 | } | 158 | } |
185 | // utf-8 it | ||
186 | 159 | ||
187 | cerr<<"Setting text: "<<text<<endl; | 160 | App app(displayname.c_str(), foreground, background); |
188 | app.setText(FbTk::FbStringUtil::XStrToFb(text), orient); | 161 | app.show(); |
162 | |||
163 | for (a = 0; a < texts_and_fonts.size(); ++a) { | ||
164 | |||
165 | vector<string> tf; | ||
166 | FbTk::StringUtil::stringtok(tf, texts_and_fonts[a], "|"); | ||
167 | if (tf.size() < 2) { | ||
168 | tf.push_back("default"); | ||
169 | } | ||
170 | |||
171 | FbTk::Font* f = new FbTk::Font(0); | ||
172 | if (f->load(tf[1])) { | ||
173 | |||
174 | if (orient && !f->validOrientation(orient)) { | ||
175 | cerr<<"Orientation not valid ("<<orient<<")"<<endl; | ||
176 | orient = FbTk::ROT0; | ||
177 | } | ||
189 | 178 | ||
179 | app.addText(FbTk::FbStringUtil::XStrToFb(tf[0]), *f, orient); | ||
180 | |||
181 | } else { | ||
182 | cerr<<"Failed to load: "<<tf[1]<<endl; | ||
183 | delete f; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | app.resize(app.width(), app.height()); | ||
190 | app.redraw(); | 188 | app.redraw(); |
191 | app.eventLoop(); | 189 | app.eventLoop(); |
192 | 190 | ||
191 | return 0; | ||
193 | } | 192 | } |
193 | |||