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
This commit is contained in:
parent
032a23d1e7
commit
7b6ab828c7
6 changed files with 222 additions and 180 deletions
|
@ -66,6 +66,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <langinfo.h>
|
#include <langinfo.h>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
@ -83,12 +84,10 @@ namespace {
|
||||||
// use to map <font1>|<font2>|<font3> => <fontthatworks>
|
// use to map <font1>|<font2>|<font3> => <fontthatworks>
|
||||||
typedef map<string, string> StringMap;
|
typedef map<string, string> StringMap;
|
||||||
typedef StringMap::iterator StringMapIt;
|
typedef StringMap::iterator StringMapIt;
|
||||||
StringMap lookup_map;
|
|
||||||
|
|
||||||
// stores <fontthatworks and the fontimp
|
// stores <fontthatworks and the fontimp
|
||||||
typedef map<string, FbTk::FontImp* > FontCache;
|
typedef map<string, FbTk::FontImp* > FontCache;
|
||||||
typedef FontCache::iterator FontCacheIt;
|
typedef FontCache::iterator FontCacheIt;
|
||||||
FontCache font_cache;
|
|
||||||
|
|
||||||
|
|
||||||
void resetEffects(FbTk::Font& font) {
|
void resetEffects(FbTk::Font& font) {
|
||||||
|
@ -100,24 +99,30 @@ void resetEffects(FbTk::Font& font) {
|
||||||
font.setShadowOffX(2);
|
font.setShadowOffX(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
StringMap s_lookup_map;
|
||||||
|
FontCache s_font_cache;
|
||||||
|
bool s_multibyte = false; // if the fontimp should be a multibyte font
|
||||||
|
bool s_utf8mode = false; // should the font use utf8 font imp
|
||||||
|
|
||||||
|
|
||||||
} // end nameless namespace
|
} // end nameless namespace
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace FbTk {
|
namespace FbTk {
|
||||||
|
|
||||||
bool Font::s_multibyte = false;
|
const char Font::DEFAULT_FONT[] = "__DEFAULT__";
|
||||||
bool Font::s_utf8mode = false;
|
|
||||||
|
|
||||||
|
|
||||||
void Font::shutdown() {
|
void Font::shutdown() {
|
||||||
|
|
||||||
FontCacheIt fit;
|
FontCacheIt fit;
|
||||||
for (fit = font_cache.begin(); fit != font_cache.end(); fit++) {
|
for (fit = s_font_cache.begin(); fit != s_font_cache.end(); ++fit) {
|
||||||
FontImp* font = fit->second;
|
FontImp* font = fit->second;
|
||||||
if (font) {
|
if (font) {
|
||||||
FontCacheIt it;
|
FontCacheIt it;
|
||||||
for (it = fit; it != font_cache.end(); ++it)
|
for (it = fit; it != s_font_cache.end(); ++it)
|
||||||
if (it->second == font)
|
if (it->second == font)
|
||||||
it->second = 0;
|
it->second = 0;
|
||||||
delete font;
|
delete font;
|
||||||
|
@ -125,6 +130,15 @@ void Font::shutdown() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Font::multibyte() {
|
||||||
|
return s_multibyte;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Font::utf8() {
|
||||||
|
return s_utf8mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Font::Font(const char *name):
|
Font::Font(const char *name):
|
||||||
m_fontimp(0),
|
m_fontimp(0),
|
||||||
m_shadow(false), m_shadow_color("black", DefaultScreen(App::instance()->display())),
|
m_shadow(false), m_shadow_color("black", DefaultScreen(App::instance()->display())),
|
||||||
|
@ -135,13 +149,15 @@ Font::Font(const char *name):
|
||||||
if (MB_CUR_MAX > 1) // more than one byte, then we're multibyte
|
if (MB_CUR_MAX > 1) // more than one byte, then we're multibyte
|
||||||
s_multibyte = true;
|
s_multibyte = true;
|
||||||
|
|
||||||
// check for utf-8 mode
|
|
||||||
#if defined(CODESET) && !defined(_WIN32)
|
|
||||||
char *locale_codeset = nl_langinfo(CODESET);
|
|
||||||
#else // openbsd doesnt have this (yet?)
|
|
||||||
char *locale_codeset = 0;
|
|
||||||
#endif // defined(CODESET) && !defined(_WIN32)
|
|
||||||
|
|
||||||
|
char *locale_codeset = 0;
|
||||||
|
|
||||||
|
// openbsd doesnt have this (yet?)
|
||||||
|
#if defined(CODESET) && !defined(_WIN32)
|
||||||
|
locale_codeset = nl_langinfo(CODESET);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// check for utf-8 mode
|
||||||
if (locale_codeset && strcmp("UTF-8", locale_codeset) == 0) {
|
if (locale_codeset && strcmp("UTF-8", locale_codeset) == 0) {
|
||||||
s_utf8mode = true;
|
s_utf8mode = true;
|
||||||
} else if (locale_codeset != 0) {
|
} else if (locale_codeset != 0) {
|
||||||
|
@ -159,15 +175,15 @@ Font::~Font() {
|
||||||
|
|
||||||
bool Font::load(const string &name) {
|
bool Font::load(const string &name) {
|
||||||
|
|
||||||
if (name.size() == 0)
|
if (name.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
StringMapIt lookup_entry;
|
StringMapIt lookup_entry;
|
||||||
FontCacheIt cache_entry;
|
FontCacheIt cache_entry;
|
||||||
|
|
||||||
// check if one of <font1>|<font2>|<font3> is already there
|
// check if one of <font1>|<font2>|<font3> is already there
|
||||||
if ((lookup_entry = lookup_map.find(name)) != lookup_map.end() &&
|
if ((lookup_entry = s_lookup_map.find(name)) != s_lookup_map.end() &&
|
||||||
(cache_entry = font_cache.find(lookup_entry->second)) != font_cache.end()) {
|
(cache_entry = s_font_cache.find(lookup_entry->second)) != s_font_cache.end()) {
|
||||||
m_fontstr = cache_entry->first;
|
m_fontstr = cache_entry->first;
|
||||||
m_fontimp = cache_entry->second;
|
m_fontimp = cache_entry->second;
|
||||||
resetEffects(*this);
|
resetEffects(*this);
|
||||||
|
@ -185,10 +201,10 @@ bool Font::load(const string &name) {
|
||||||
FbTk::StringUtil::removeTrailingWhitespace(*name_it);
|
FbTk::StringUtil::removeTrailingWhitespace(*name_it);
|
||||||
FbTk::StringUtil::removeFirstWhitespace(*name_it);
|
FbTk::StringUtil::removeFirstWhitespace(*name_it);
|
||||||
|
|
||||||
if ((cache_entry = font_cache.find(*name_it)) != font_cache.end()) {
|
if ((cache_entry = s_font_cache.find(*name_it)) != s_font_cache.end()) {
|
||||||
m_fontstr = cache_entry->first;
|
m_fontstr = cache_entry->first;
|
||||||
m_fontimp = cache_entry->second;
|
m_fontimp = cache_entry->second;
|
||||||
lookup_map[name] = m_fontstr;
|
s_lookup_map[name] = m_fontstr;
|
||||||
resetEffects(*this);
|
resetEffects(*this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -210,32 +226,33 @@ bool Font::load(const string &name) {
|
||||||
#ifdef USE_XFT
|
#ifdef USE_XFT
|
||||||
if ((*name_it)[0] != '-') {
|
if ((*name_it)[0] != '-') {
|
||||||
|
|
||||||
if (*name_it == "__DEFAULT__")
|
if (*name_it == Font::DEFAULT_FONT)
|
||||||
realname = "monospace";
|
realname = "monospace";
|
||||||
|
|
||||||
tmp_font = new XftFontImp(0, s_utf8mode);
|
tmp_font = new XftFontImp(0, utf8());
|
||||||
}
|
}
|
||||||
#endif // USE_XFT
|
#endif // USE_XFT
|
||||||
|
|
||||||
if (!tmp_font) {
|
if (!tmp_font) {
|
||||||
if (*name_it == "__DEFAULT__")
|
if (*name_it == Font::DEFAULT_FONT)
|
||||||
realname = "fixed";
|
realname = "fixed";
|
||||||
|
|
||||||
#ifdef USE_XMB
|
#ifdef USE_XMB
|
||||||
|
|
||||||
if (s_multibyte || s_utf8mode) {
|
if (multibyte() || utf8()) {
|
||||||
tmp_font = new XmbFontImp(0, s_utf8mode);
|
tmp_font = new XmbFontImp(0, utf8());
|
||||||
} else // basic font implementation
|
|
||||||
#endif // USE_XMB
|
|
||||||
{
|
|
||||||
tmp_font = new XFontImp();
|
|
||||||
}
|
}
|
||||||
|
#endif // USE_XMB
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tmp_font) {
|
||||||
|
tmp_font = new XFontImp();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp_font && tmp_font->load(realname.c_str())) {
|
if (tmp_font && tmp_font->load(realname.c_str())) {
|
||||||
lookup_map[name] = (*name_it);
|
s_lookup_map[name] = (*name_it);
|
||||||
m_fontimp = tmp_font;
|
m_fontimp = tmp_font;
|
||||||
font_cache[(*name_it)] = tmp_font;
|
s_font_cache[(*name_it)] = tmp_font;
|
||||||
m_fontstr = name;
|
m_fontstr = name;
|
||||||
resetEffects(*this);
|
resetEffects(*this);
|
||||||
return true;
|
return true;
|
||||||
|
@ -251,6 +268,10 @@ unsigned int Font::textWidth(const char* text, unsigned int size) const {
|
||||||
return m_fontimp->textWidth(text, size);
|
return m_fontimp->textWidth(text, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int Font::textWidth(const BiDiString &text) const {
|
||||||
|
return textWidth(text.visual().c_str(), text.visual().size());
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int Font::height() const {
|
unsigned int Font::height() const {
|
||||||
return m_fontimp->height();
|
return m_fontimp->height();
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,17 +43,19 @@ class FbDrawable;
|
||||||
class Font {
|
class Font {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
static const char DEFAULT_FONT[];
|
||||||
|
|
||||||
|
|
||||||
/// called at FbTk::App destruction time, cleans up cache
|
/// called at FbTk::App destruction time, cleans up cache
|
||||||
static void shutdown();
|
static void shutdown();
|
||||||
|
|
||||||
/// @return true if multibyte is enabled, else false
|
/// @return true if multibyte is enabled, else false
|
||||||
static bool multibyte() { return s_multibyte; }
|
static bool multibyte();
|
||||||
/// @return true if utf-8 mode is enabled, else false
|
/// @return true if utf-8 mode is enabled, else false
|
||||||
static bool utf8() { return s_utf8mode; }
|
static bool utf8();
|
||||||
|
|
||||||
|
|
||||||
|
explicit Font(const char* name = DEFAULT_FONT);
|
||||||
explicit Font(const char *name = "__DEFAULT__");
|
|
||||||
virtual ~Font();
|
virtual ~Font();
|
||||||
/**
|
/**
|
||||||
Load a font
|
Load a font
|
||||||
|
@ -76,9 +78,7 @@ public:
|
||||||
@return size of text in pixels
|
@return size of text in pixels
|
||||||
*/
|
*/
|
||||||
unsigned int textWidth(const char* text, unsigned int size) const;
|
unsigned int textWidth(const char* text, unsigned int size) const;
|
||||||
unsigned int textWidth(const BiDiString &text) const {
|
unsigned int textWidth(const BiDiString &text) const;
|
||||||
return textWidth(text.visual().c_str(), text.visual().size());
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int height() const;
|
unsigned int height() const;
|
||||||
int ascent() const;
|
int ascent() const;
|
||||||
|
@ -119,9 +119,6 @@ private:
|
||||||
FbTk::FontImp* m_fontimp; ///< font implementation
|
FbTk::FontImp* m_fontimp; ///< font implementation
|
||||||
std::string m_fontstr; ///< font name
|
std::string m_fontstr; ///< font name
|
||||||
|
|
||||||
static bool s_multibyte; ///< if the fontimp should be a multibyte font
|
|
||||||
static bool s_utf8mode; ///< should the font use utf8 font imp
|
|
||||||
|
|
||||||
int m_angle; ///< rotation angle
|
int m_angle; ///< rotation angle
|
||||||
bool m_shadow; ///< shadow text
|
bool m_shadow; ///< shadow text
|
||||||
Color m_shadow_color; ///< shadow color
|
Color m_shadow_color; ///< shadow color
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "TextUtils.hh"
|
#include "TextUtils.hh"
|
||||||
#include "Font.hh"
|
#include "Font.hh"
|
||||||
#include "GContext.hh"
|
#include "GContext.hh"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
namespace FbTk {
|
namespace FbTk {
|
||||||
|
|
||||||
|
@ -62,16 +63,18 @@ void TextButton::setJustify(FbTk::Justify just) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextButton::setOrientation(FbTk::Orientation orient) {
|
bool TextButton::setOrientation(FbTk::Orientation orient) {
|
||||||
|
|
||||||
if (orient == m_orientation
|
if (orient == m_orientation
|
||||||
|| !m_font->validOrientation(orient))
|
|| !m_font->validOrientation(orient))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
invalidateBackground();
|
invalidateBackground();
|
||||||
|
|
||||||
if (((m_orientation == FbTk::ROT0 || m_orientation == FbTk::ROT180) &&
|
if (((m_orientation == FbTk::ROT0 || m_orientation == FbTk::ROT180) &&
|
||||||
(orient == FbTk::ROT90 || orient == FbTk::ROT270)) ||
|
(orient == FbTk::ROT90 || orient == FbTk::ROT270)) ||
|
||||||
((m_orientation == FbTk::ROT90 || m_orientation == FbTk::ROT270) &&
|
((m_orientation == FbTk::ROT90 || m_orientation == FbTk::ROT270) &&
|
||||||
(orient == FbTk::ROT0 || orient == FbTk::ROT180))) {
|
(orient == FbTk::ROT0 || orient == FbTk::ROT180))) {
|
||||||
// flip width and height
|
|
||||||
m_orientation = orient;
|
m_orientation = orient;
|
||||||
resize(height(), width());
|
resize(height(), width());
|
||||||
} else {
|
} else {
|
||||||
|
@ -112,8 +115,7 @@ void TextButton::setTextPadding(unsigned int padding) {
|
||||||
|
|
||||||
/// clear window and redraw text
|
/// clear window and redraw text
|
||||||
void TextButton::clear() {
|
void TextButton::clear() {
|
||||||
TextButton::clearArea(0, 0,
|
TextButton::clearArea(0, 0, width(), height());
|
||||||
width(), height());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextButton::clearArea(int x, int y,
|
void TextButton::clearArea(int x, int y,
|
||||||
|
@ -135,34 +137,58 @@ void TextButton::renderForeground(FbWindow &win, FbDrawable &drawable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextButton::drawText(int x_offset, int y_offset, FbDrawable *drawable) {
|
void TextButton::drawText(int x_offset, int y_offset, FbDrawable *drawable) {
|
||||||
const FbString& visual = text().visual();
|
|
||||||
unsigned int textlen = visual.size();
|
|
||||||
unsigned int textw = width();
|
|
||||||
unsigned int texth = height();
|
|
||||||
translateSize(m_orientation, textw, texth);
|
|
||||||
|
|
||||||
int align_x = FbTk::doAlignment(textw - x_offset - m_left_padding - m_right_padding,
|
|
||||||
bevel(), justify(), font(),
|
|
||||||
visual.data(), visual.size(),
|
|
||||||
textlen); // return new text len
|
|
||||||
|
|
||||||
// center text by default
|
|
||||||
int center_pos = texth/2 + font().ascent()/2 - 1;
|
|
||||||
|
|
||||||
int textx = align_x + x_offset + m_left_padding;
|
|
||||||
int texty = center_pos + y_offset;
|
|
||||||
|
|
||||||
if (drawable == 0)
|
if (drawable == 0)
|
||||||
drawable = this;
|
drawable = this;
|
||||||
|
|
||||||
// give it ROT0 style coords
|
const FbString& visual = text().visual();
|
||||||
translateCoords(m_orientation, textx, texty, textw, texth);
|
unsigned int textlen = visual.size();
|
||||||
|
unsigned int button_width = width();
|
||||||
|
unsigned int button_height = height();
|
||||||
|
|
||||||
font().drawText(*drawable,
|
translateSize(m_orientation, button_width, button_height);
|
||||||
screenNumber(),
|
|
||||||
gc(), // graphic context
|
// horizontal alignment, cut off text if needed
|
||||||
visual.c_str(), textlen, // string and string size
|
int align_x = FbTk::doAlignment(button_width - x_offset - m_left_padding - m_right_padding,
|
||||||
textx, texty, m_orientation); // position
|
bevel(), justify(), font(),
|
||||||
|
visual.data(), visual.size(),
|
||||||
|
textlen); // return new text len
|
||||||
|
|
||||||
|
//
|
||||||
|
// we center the text vertically. to do this we have to nudge the
|
||||||
|
// baseline a little bit down so the "middle" of the glyph is placed
|
||||||
|
// on the middle of the button. we "assume", that ascent/2 is roughly
|
||||||
|
// the middle of the glyph. example:
|
||||||
|
//
|
||||||
|
// +== ascent <--------->== +=====================
|
||||||
|
// | | | |
|
||||||
|
// | | ggggg | | ascent <--------->
|
||||||
|
// | | g gg | | | |
|
||||||
|
// | baseline < glyph | | | ggggg |
|
||||||
|
// | | g | -- middle of button -- | | g gg |
|
||||||
|
// | descent < ggggg | | baseline < glyph |
|
||||||
|
// | height |_________| | | g |
|
||||||
|
// | | descent < ggggg |
|
||||||
|
// | | height |_________|
|
||||||
|
// | |
|
||||||
|
// +======================= +=====================
|
||||||
|
//
|
||||||
|
// ascent = 4
|
||||||
|
// button_height = 11
|
||||||
|
// baseline = (11 + 4) / 2 - 1 = 6
|
||||||
|
//
|
||||||
|
|
||||||
|
int baseline_x = align_x + x_offset + m_left_padding;
|
||||||
|
int baseline_y = ((button_height + font().ascent()) / 2) - 1 + y_offset;
|
||||||
|
|
||||||
|
// TODO: remove debug output fprintf(stderr, "%d | %d %d %d\n", height(), font().height(), font().ascent(), font().descent());
|
||||||
|
|
||||||
|
// give it ROT0 style coords
|
||||||
|
translateCoords(m_orientation, baseline_x, baseline_y, button_width, button_height);
|
||||||
|
|
||||||
|
font().drawText(*drawable, screenNumber(), gc(),
|
||||||
|
visual.c_str(), textlen,
|
||||||
|
baseline_x, baseline_y, m_orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -170,11 +196,11 @@ bool TextButton::textExceeds(int x_offset) {
|
||||||
|
|
||||||
const FbString& visual = text().visual();
|
const FbString& visual = text().visual();
|
||||||
unsigned int textlen = visual.size();
|
unsigned int textlen = visual.size();
|
||||||
unsigned int textw = width();
|
unsigned int button_width = width();
|
||||||
unsigned int texth = height();
|
unsigned int button_height = height();
|
||||||
translateSize(m_orientation, textw, texth);
|
translateSize(m_orientation, button_width, button_height);
|
||||||
|
|
||||||
FbTk::doAlignment(textw - x_offset - m_left_padding - m_right_padding,
|
FbTk::doAlignment(button_width - x_offset - m_left_padding - m_right_padding,
|
||||||
bevel(), justify(), font(), visual.data(), visual.size(),
|
bevel(), justify(), font(), visual.data(), visual.size(),
|
||||||
textlen); // return new text len
|
textlen); // return new text len
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,8 @@ public:
|
||||||
|
|
||||||
void exposeEvent(XExposeEvent &event);
|
void exposeEvent(XExposeEvent &event);
|
||||||
|
|
||||||
void renderForeground(FbDrawable &drawable);
|
//void renderForeground(FbDrawable &drawable);
|
||||||
|
void renderForeground(FbWindow &win, FbDrawable &drawable);
|
||||||
|
|
||||||
FbTk::Justify justify() const { return m_justify; }
|
FbTk::Justify justify() const { return m_justify; }
|
||||||
const BiDiString &text() const { return m_text; }
|
const BiDiString &text() const { return m_text; }
|
||||||
|
@ -65,7 +66,6 @@ public:
|
||||||
unsigned int textWidth() const;
|
unsigned int textWidth() const;
|
||||||
int bevel() const { return m_bevel; }
|
int bevel() const { return m_bevel; }
|
||||||
|
|
||||||
void renderForeground(FbWindow &win, FbDrawable &drawable);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void drawText(int x_offset, int y_offset, FbDrawable *drawable_override);
|
virtual void drawText(int x_offset, int y_offset, FbDrawable *drawable_override);
|
||||||
|
|
|
@ -170,14 +170,12 @@ Toolbar::Frame::Frame(FbTk::EventHandler &evh, int screen_num):
|
||||||
{
|
{
|
||||||
|
|
||||||
FbTk::EventManager &evm = *FbTk::EventManager::instance();
|
FbTk::EventManager &evm = *FbTk::EventManager::instance();
|
||||||
// add windows to eventmanager
|
|
||||||
evm.add(evh, window);
|
evm.add(evh, window);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Toolbar::Frame::~Frame() {
|
Toolbar::Frame::~Frame() {
|
||||||
FbTk::EventManager &evm = *FbTk::EventManager::instance();
|
FbTk::EventManager &evm = *FbTk::EventManager::instance();
|
||||||
// remove windows from eventmanager
|
|
||||||
evm.remove(window);
|
evm.remove(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,13 +19,16 @@
|
||||||
// DEALINGS IN THE SOFTWARE.
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
#include "FbTk/App.hh"
|
#include "FbTk/App.hh"
|
||||||
|
#include "FbTk/FbString.hh"
|
||||||
#include "FbTk/FbWindow.hh"
|
#include "FbTk/FbWindow.hh"
|
||||||
#include "FbTk/Font.hh"
|
#include "FbTk/Font.hh"
|
||||||
|
#include "FbTk/TextButton.hh"
|
||||||
#include "FbTk/EventHandler.hh"
|
#include "FbTk/EventHandler.hh"
|
||||||
#include "FbTk/EventManager.hh"
|
#include "FbTk/EventManager.hh"
|
||||||
#include "FbTk/GContext.hh"
|
#include "FbTk/GContext.hh"
|
||||||
#include "FbTk/Color.hh"
|
#include "FbTk/Color.hh"
|
||||||
#include "FbTk/FbString.hh"
|
#include "FbTk/FbString.hh"
|
||||||
|
#include "FbTk/StringUtil.hh"
|
||||||
|
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
|
@ -34,124 +37,103 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
class App:public FbTk::App, public FbTk::EventHandler {
|
|
||||||
|
class App:public FbTk::App, public FbTk::FbWindow, public FbTk::EventHandler {
|
||||||
public:
|
public:
|
||||||
App(const char *displayname, const string &foreground, const string background):
|
App(const char *displayname, const string& foreground, const string& background):
|
||||||
FbTk::App(displayname),
|
FbTk::App(displayname),
|
||||||
m_win(DefaultScreen(display()),
|
FbTk::FbWindow(DefaultScreen(this->FbTk::App::display()), 0, 0, 640, 480, KeyPressMask|ExposureMask|StructureNotifyMask),
|
||||||
0, 0, 640, 480, KeyPressMask | ExposureMask) {
|
m_gc(drawable()),
|
||||||
m_background = background;
|
m_foreground(foreground.c_str(), screenNumber()),
|
||||||
m_foreground = foreground;
|
m_background(background.c_str(), screenNumber()) {
|
||||||
m_orient = FbTk::ROT0;
|
|
||||||
m_win.show();
|
m_gc.setLineAttributes(1, FbTk::GContext::JOINMITER, FbTk::GContext::LINESOLID, FbTk::GContext::CAPNOTLAST);
|
||||||
m_win.setBackgroundColor(FbTk::Color(background.c_str(), m_win.screenNumber()));
|
m_gc.setForeground(m_foreground);
|
||||||
FbTk::EventManager::instance()->add(*this, m_win);
|
m_gc.setBackground(m_background);
|
||||||
}
|
setBackgroundColor(m_background);
|
||||||
~App() {
|
|
||||||
|
FbTk::EventManager::instance()->add(*this, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~App() { }
|
||||||
|
|
||||||
void keyPressEvent(XKeyEvent &ke) {
|
void keyPressEvent(XKeyEvent &ke) {
|
||||||
KeySym ks;
|
KeySym ks;
|
||||||
char keychar[1];
|
char keychar[1];
|
||||||
XLookupString(&ke, keychar, 1, &ks, 0);
|
XLookupString(&ke, keychar, 1, &ks, 0);
|
||||||
if (ks == XK_Escape)
|
if (ks == XK_Escape) {
|
||||||
end();
|
end();
|
||||||
/*
|
|
||||||
else { // toggle antialias
|
|
||||||
m_font.setAntialias(!m_font.isAntialias());
|
|
||||||
cerr<<boolalpha;
|
|
||||||
cerr<<"antialias: "<<m_font.isAntialias()<<endl;
|
|
||||||
redraw();
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void handleEvent(XEvent& event) {
|
||||||
|
if (event.type == ConfigureNotify) {
|
||||||
|
resize(event.xconfigure.width, event.xconfigure.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void exposeEvent(XExposeEvent &event) {
|
void exposeEvent(XExposeEvent &event) {
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void redraw() {
|
void redraw() {
|
||||||
size_t text_w = m_font.textWidth(m_text.c_str(), m_text.size());
|
size_t i;
|
||||||
int mult = 1;
|
for (i = 0; i < m_buttons.size(); ++i) {
|
||||||
if (m_orient == FbTk::ROT180)
|
FbTk::TextButton* b = m_buttons[i];
|
||||||
mult = -1;
|
b->clear();
|
||||||
size_t text_h = m_font.height();
|
b->drawLine(m_gc.gc(), 0, b->height() / 2, b->width(), b->height() / 2);
|
||||||
int x = 640/2 - mult* text_w/2;
|
}
|
||||||
int y = 480/2 - mult*text_h/2;
|
this->clear();
|
||||||
m_win.clear();
|
|
||||||
FbTk::GContext wingc(m_win.drawable());
|
|
||||||
|
|
||||||
int bx1 = 0;
|
|
||||||
int by1 = 0;
|
|
||||||
int bx2 = text_w;
|
|
||||||
int by2 = 0;
|
|
||||||
|
|
||||||
switch (m_orient) {
|
|
||||||
case FbTk::ROT90:
|
|
||||||
by2 = bx2;
|
|
||||||
bx2 = 0;
|
|
||||||
break;
|
|
||||||
case FbTk::ROT180:
|
|
||||||
bx2 = -bx2;
|
|
||||||
break;
|
|
||||||
case FbTk::ROT270:
|
|
||||||
by2 = -bx2;
|
|
||||||
bx2 = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void resize(unsigned int width, unsigned int height) {
|
||||||
m_win.drawLine(wingc.gc(),
|
FbTk::FbWindow::resize(width, height);
|
||||||
x, y + m_font.descent(),
|
unsigned w = width / m_buttons.size();
|
||||||
x + text_w, y + m_font.descent());
|
size_t i;
|
||||||
m_win.drawLine(wingc.gc(),
|
for (i = 0; i < m_buttons.size(); ++i) {
|
||||||
x, y - text_h,
|
m_buttons[i]->moveResize(i * w, 0, w, height);
|
||||||
x + text_w, y - text_h);
|
}
|
||||||
*/
|
redraw();
|
||||||
// draw the baseline in red
|
|
||||||
wingc.setForeground(FbTk::Color("red", m_win.screenNumber()));
|
|
||||||
m_win.drawLine(wingc.gc(),
|
|
||||||
x + bx1, y + by1, x + bx2, y+by2);
|
|
||||||
wingc.setForeground(FbTk::Color(m_foreground.c_str(), m_win.screenNumber()));
|
|
||||||
cerr<<"text size "<<text_w<<"x"<<text_h<<endl;
|
|
||||||
m_font.drawText(m_win,
|
|
||||||
0, wingc.gc(),
|
|
||||||
m_text.c_str(), m_text.size(),
|
|
||||||
x, y, m_orient);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FbTk::Font &font() { return m_font; }
|
void addText(const FbTk::BiDiString& text, FbTk::Font& font, const FbTk::Orientation orient) {
|
||||||
void setText(const std::string& text, const FbTk::Orientation orient) { m_text = text; m_orient = orient; }
|
|
||||||
|
FbTk::FbWindow* win = this;
|
||||||
|
FbTk::TextButton* button = new FbTk::TextButton(*win, font, text);
|
||||||
|
|
||||||
|
button->setGC(m_gc.gc());
|
||||||
|
button->setOrientation(orient);
|
||||||
|
button->setBackgroundColor(m_background);
|
||||||
|
button->show();
|
||||||
|
|
||||||
|
m_buttons.push_back(button);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
string m_foreground, m_background;
|
vector<FbTk::TextButton*> m_buttons;
|
||||||
FbTk::FbWindow m_win;
|
FbTk::GContext m_gc;
|
||||||
FbTk::Font m_font;
|
FbTk::Color m_foreground;
|
||||||
FbTk::Orientation m_orient;
|
FbTk::Color m_background;
|
||||||
string m_text;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
//bool antialias = false;
|
|
||||||
|
vector<string> texts_and_fonts;
|
||||||
FbTk::Orientation orient = FbTk::ROT0;
|
FbTk::Orientation orient = FbTk::ROT0;
|
||||||
bool xft = false;
|
|
||||||
string fontname("");
|
|
||||||
string displayname("");
|
string displayname("");
|
||||||
string background("black");
|
string background("white");
|
||||||
string foreground("white");
|
string foreground("black");
|
||||||
string text("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.-_¯åäöÅÄÖ^~+=`\"!#¤%&/()=¡@£$½¥{[]}¶½§±");
|
|
||||||
for (int a=1; a<argc; ++a) {
|
int a;
|
||||||
if (strcmp("-font", argv[a])==0 && a + 1 < argc) {
|
for (a = 1; a < argc; ++a) {
|
||||||
fontname = argv[++a];
|
if (strcmp("-display", argv[a]) == 0 && a + 1 < argc) {
|
||||||
} else if (strcmp("-xft", argv[a])==0) {
|
|
||||||
xft = true;
|
|
||||||
} else if (strcmp("-display", argv[a]) == 0 && a + 1 < argc) {
|
|
||||||
displayname = argv[++a];
|
displayname = argv[++a];
|
||||||
} else if (strcmp("-text", argv[a]) == 0 && a + 1 < argc) {
|
|
||||||
text = argv[++a];
|
|
||||||
} else if (strcmp("-orient", argv[a]) == 0) {
|
} else if (strcmp("-orient", argv[a]) == 0) {
|
||||||
orient = (FbTk::Orientation) (atoi(argv[++a]) % 4);
|
orient = (FbTk::Orientation) (atoi(argv[++a]) % 4);
|
||||||
} else if (strcmp("-bg", argv[a]) == 0 && a + 1 < argc) {
|
} else if (strcmp("-bg", argv[a]) == 0 && a + 1 < argc) {
|
||||||
|
@ -159,35 +141,53 @@ int main(int argc, char **argv) {
|
||||||
} else if (strcmp("-fg", argv[a]) == 0 && a + 1 < argc) {
|
} else if (strcmp("-fg", argv[a]) == 0 && a + 1 < argc) {
|
||||||
foreground = argv[++a];
|
foreground = argv[++a];
|
||||||
} else if (strcmp("-h", argv[a]) == 0) {
|
} else if (strcmp("-h", argv[a]) == 0) {
|
||||||
cerr<<"Arguments: "<<endl;
|
cerr<<"Arguments: \"text|fontname\" [\"text|fontname2\"]"<<endl;
|
||||||
cerr<<"-font <fontname>"<<endl;
|
|
||||||
// cerr<<"-antialias"<<endl;
|
|
||||||
cerr<<"-display <display>"<<endl;
|
cerr<<"-display <display>"<<endl;
|
||||||
cerr<<"-text <text>"<<endl;
|
|
||||||
cerr<<"-orient"<<endl;
|
cerr<<"-orient"<<endl;
|
||||||
cerr<<"-fg <foreground color>"<<endl;
|
cerr<<"-fg <foreground color>"<<endl;
|
||||||
cerr<<"-bg <background color>"<<endl;
|
cerr<<"-bg <background color>"<<endl;
|
||||||
cerr<<"-h"<<endl;
|
cerr<<"-h"<<endl;
|
||||||
exit(0);
|
exit(0);
|
||||||
|
} else {
|
||||||
|
texts_and_fonts.push_back(argv[a]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (texts_and_fonts.empty()) {
|
||||||
|
texts_and_fonts.push_back("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.-_¯åäöÅÄÖ^~+=`\"!#¤%&/()=¡@£$½¥{[]}¶½§±|default");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
App app(displayname.c_str(), foreground, background);
|
App app(displayname.c_str(), foreground, background);
|
||||||
//app.font().setAntialias(antialias);
|
app.show();
|
||||||
if (!app.font().load(fontname.c_str()))
|
|
||||||
cerr<<"Failed to load: "<<fontname<<endl;
|
for (a = 0; a < texts_and_fonts.size(); ++a) {
|
||||||
if (orient && !app.font().validOrientation(orient)) {
|
|
||||||
|
vector<string> tf;
|
||||||
|
FbTk::StringUtil::stringtok(tf, texts_and_fonts[a], "|");
|
||||||
|
if (tf.size() < 2) {
|
||||||
|
tf.push_back("default");
|
||||||
|
}
|
||||||
|
|
||||||
|
FbTk::Font* f = new FbTk::Font(0);
|
||||||
|
if (f->load(tf[1])) {
|
||||||
|
|
||||||
|
if (orient && !f->validOrientation(orient)) {
|
||||||
cerr<<"Orientation not valid ("<<orient<<")"<<endl;
|
cerr<<"Orientation not valid ("<<orient<<")"<<endl;
|
||||||
orient = FbTk::ROT0;
|
orient = FbTk::ROT0;
|
||||||
}
|
}
|
||||||
// utf-8 it
|
|
||||||
|
|
||||||
cerr<<"Setting text: "<<text<<endl;
|
app.addText(FbTk::FbStringUtil::XStrToFb(tf[0]), *f, orient);
|
||||||
app.setText(FbTk::FbStringUtil::XStrToFb(text), orient);
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cerr<<"Failed to load: "<<tf[1]<<endl;
|
||||||
|
delete f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app.resize(app.width(), app.height());
|
||||||
app.redraw();
|
app.redraw();
|
||||||
app.eventLoop();
|
app.eventLoop();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue